From 0c836454b26e0756131ce4b5f3ae312651da9d32 Mon Sep 17 00:00:00 2001 From: Akihiro Motoki Date: Wed, 21 Jun 2017 13:54:19 +0000 Subject: [PATCH] Switch render() arguments to the new way Previously template.render() takes Context or RequestContext object but after Django 1.8 the method takes a dict and request as separate arguments. The old way will be dropped in Django 1.10. This commit update the usage based on the Django 1.8 release notes [1]. commit 95d78a140fdb6f24dc3bd87d654e9f927ddfbfa4 addresses this deprecations but it turns out all similar places are not switched. I searched the code base more carefully and found more. I hope this clean up all of them. After this change, extra_context which was passed to (Request)Context previously is no longer available in HttpResponse object. Volume unit test is tightly coupled with the context information and checks rendered actions using the context. Thus the corresponding tests no longer work. Since we can use only HttpResponse.content (which is a rendered HTML), the new tests just check various strings like ID, link and label of a specific action. This is tricky, but this is now the only thing we can do. [1] https://docs.djangoproject.com/en/1.8/ref/templates/upgrading/#get-template-and-select-template Change-Id: I350c22dc3d7db7b93ca4b823dac1e3d88beef1a7 --- horizon/browsers/base.py | 3 +- horizon/browsers/breadcrumb.py | 3 +- horizon/forms/fields.py | 5 +- horizon/tables/base.py | 9 ++-- horizon/utils/csvbase.py | 6 +-- horizon/workflows/base.py | 3 +- .../dashboards/project/volumes/tests.py | 50 ++++++++----------- 7 files changed, 30 insertions(+), 49 deletions(-) diff --git a/horizon/browsers/base.py b/horizon/browsers/base.py index 5a28c6797f..907428c89e 100644 --- a/horizon/browsers/base.py +++ b/horizon/browsers/base.py @@ -144,5 +144,4 @@ class ResourceBrowser(html.HTMLElement): def render(self): browser_template = template.loader.get_template(self.template) extra_context = {self.context_var_name: self} - context = template.RequestContext(self.request, extra_context) - return browser_template.render(context) + return browser_template.render(extra_context, self.request) diff --git a/horizon/browsers/breadcrumb.py b/horizon/browsers/breadcrumb.py index f4e13c556d..567da56e56 100644 --- a/horizon/browsers/breadcrumb.py +++ b/horizon/browsers/breadcrumb.py @@ -42,5 +42,4 @@ class Breadcrumb(html.HTMLElement): """Renders the table using the template from the table options.""" breadcrumb_template = template.loader.get_template(self.template) extra_context = {"breadcrumb": self} - context = template.RequestContext(self.request, extra_context) - return breadcrumb_template.render(context) + return breadcrumb_template.render(extra_context, self.request) diff --git a/horizon/forms/fields.py b/horizon/forms/fields.py index dcf351e0d5..a9235b097f 100644 --- a/horizon/forms/fields.py +++ b/horizon/forms/fields.py @@ -26,7 +26,6 @@ from django.forms import fields from django.forms import forms from django.forms.utils import flatatt from django.forms import widgets -from django.template import Context from django.template.loader import get_template from django.utils.encoding import force_text from django.utils.functional import Promise @@ -291,14 +290,14 @@ class ThemableSelectWidget(SelectWidget): id = attrs.pop('id', 'id_%s' % name) template = get_template('horizon/common/fields/_themable_select.html') - context = Context({ + context = { 'name': name, 'options': new_choices, 'id': id, 'value': value, 'initial_value': initial_value, 'select_attrs': attrs, - }) + } return template.render(context) diff --git a/horizon/tables/base.py b/horizon/tables/base.py index 92a4a22e14..d8f067646c 100644 --- a/horizon/tables/base.py +++ b/horizon/tables/base.py @@ -1387,8 +1387,7 @@ class DataTable(object): table_template = template.loader.get_template(self._meta.template) extra_context = {self._meta.context_var_name: self, 'hidden_title': self._meta.hidden_title} - context = template.RequestContext(self.request, extra_context) - return table_template.render(context) + return table_template.render(extra_context, self.request) def get_absolute_url(self): """Returns the canonical URL for this table. @@ -1545,9 +1544,8 @@ class DataTable(object): if self._meta.table_actions_menu_label: extra_context['table_actions_menu_label'] = \ self._meta.table_actions_menu_label - context = template.RequestContext(self.request, extra_context) self.set_multiselect_column_visibility(len(bound_actions) > 0) - return table_actions_template.render(context) + return table_actions_template.render(extra_context, self.request) def render_row_actions(self, datum, row=False): """Renders the actions specified in ``Meta.row_actions``. @@ -1565,8 +1563,7 @@ class DataTable(object): bound_actions = self.get_row_actions(datum) extra_context = {"row_actions": bound_actions, "row_id": self.get_object_id(datum)} - context = template.RequestContext(self.request, extra_context) - return row_actions_template.render(context) + return row_actions_template.render(extra_context, self.request) @staticmethod def parse_action(action_string): diff --git a/horizon/utils/csvbase.py b/horizon/utils/csvbase.py index ab74a08030..4b25d24a30 100644 --- a/horizon/utils/csvbase.py +++ b/horizon/utils/csvbase.py @@ -84,8 +84,7 @@ class BaseCsvResponse(CsvDataMixin, HttpResponse): if template: # Display some header info if provided as a template header_template = django_template.loader.get_template(template) - context = django_template.RequestContext(request, self.context) - self.header = header_template.render(context) + self.header = header_template.render(self.context, request) if self.header: self.out.write(self.encode(self.header)) @@ -117,8 +116,7 @@ class BaseCsvStreamingResponse(CsvDataMixin, StreamingHttpResponse): if template: # Display some header info if provided as a template header_template = django_template.loader.get_template(template) - context = django_template.RequestContext(request, self.context) - self.header = header_template.render(context) + self.header = header_template.render(self.context, request) self._closable_objects.append(self.out) diff --git a/horizon/workflows/base.py b/horizon/workflows/base.py index 4c8c4e7823..6e6ef1d358 100644 --- a/horizon/workflows/base.py +++ b/horizon/workflows/base.py @@ -181,8 +181,7 @@ class Action(forms.Form): extra_context = extra_context or {} if self.help_text_template: tmpl = template.loader.get_template(self.help_text_template) - context = template.RequestContext(self.request, extra_context) - text += tmpl.render(context) + text += tmpl.render(extra_context, self.request) else: text += linebreaks(force_text(self.help_text)) return safe(text) diff --git a/openstack_dashboard/dashboards/project/volumes/tests.py b/openstack_dashboard/dashboards/project/volumes/tests.py index bd97492240..1336394358 100644 --- a/openstack_dashboard/dashboards/project/volumes/tests.py +++ b/openstack_dashboard/dashboards/project/volumes/tests.py @@ -14,7 +14,6 @@ import copy import six -from six import moves import django from django.conf import settings @@ -1248,23 +1247,6 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase): server.id) self.assertEqual(res.status_code, 200) - def _get_volume_row_action_from_ajax(self, res, action_name, row_id): - def _matches_row_id(context_row): - return (len(context_row.dicts) > 1 and - hasattr(context_row.dicts[1], 'get') and - context_row.dicts[1].get('row_id', None) == row_id) - - matching = list(moves.filter(lambda r: _matches_row_id(r), - res.context)) - self.assertGreater(len(matching), 1, - "Expected at least one row matching %s" % row_id) - row = matching[-1].dicts[1] - matching_actions = list(moves.filter(lambda a: a.name == action_name, - row['row_actions'])) - self.assertEqual(1, len(matching_actions), - "Expected one row action named '%s'" % action_name) - return matching_actions[0] - @test.create_stubs({cinder: ('tenant_absolute_limits', 'volume_get',)}) def test_create_snapshot_button_attributes(self): @@ -1282,15 +1264,16 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase): res = self.client.get(res_url, {}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - snapshot_action = self._get_volume_row_action_from_ajax( - res, 'snapshots', volume.id) - self.assertEqual('horizon:project:volumes:create_snapshot', - snapshot_action.url) - self.assertEqual(set(['ajax-modal']), set(snapshot_action.classes)) - self.assertEqual('Create Snapshot', - six.text_type(snapshot_action.verbose_name)) - self.assertEqual((('volume', 'volume:create_snapshot'),), - snapshot_action.policy_rules) + action_name = ('%(table)s__row_%(id)s__action_%(action)s' % + {'table': 'volumes', 'id': volume.id, + 'action': 'snapshots'}) + content = res.content.decode('utf-8') + self.assertIn(action_name, content) + self.assertIn('Create Snapshot', content) + self.assertIn(reverse('horizon:project:volumes:create_snapshot', + args=[volume.id]), + content) + self.assertNotIn('disabled', content) @test.create_stubs({cinder: ('tenant_absolute_limits', 'volume_get',)}) @@ -1309,9 +1292,16 @@ class VolumeViewTests(test.ResetImageAPIVersionMixin, test.TestCase): res = self.client.get(res_url, {}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - snapshot_action = self._get_volume_row_action_from_ajax( - res, 'snapshots', volume.id) - self.assertIn('disabled', snapshot_action.classes, + action_name = ('%(table)s__row_%(id)s__action_%(action)s' % + {'table': 'volumes', 'id': volume.id, + 'action': 'snapshots'}) + content = res.content.decode('utf-8') + self.assertIn(action_name, content) + self.assertIn('Create Snapshot (Quota exceeded)', content) + self.assertIn(reverse('horizon:project:volumes:create_snapshot', + args=[volume.id]), + content) + self.assertIn('disabled', content, 'The create snapshot button should be disabled') @test.create_stubs({cinder: ('tenant_absolute_limits',