From 6a7495051304d75865add6ff96422018984e1663 Mon Sep 17 00:00:00 2001 From: Shivang Bharadwaj Date: Thu, 29 Dec 2016 02:33:20 +0530 Subject: [PATCH] Fixed #27258 -- Prohibited django.Template.render() with non-dict context. Thanks Shivang Bharadwaj for the initial patch. --- django/template/context.py | 2 ++ django/views/csrf.py | 5 +++-- docs/releases/1.11.txt | 9 +++++++++ tests/template_backends/test_django.py | 20 +++++++++++++++++++- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/django/template/context.py b/django/template/context.py index 134aac4b36..166f60fe75 100644 --- a/django/template/context.py +++ b/django/template/context.py @@ -281,6 +281,8 @@ def make_context(context, request=None, **kwargs): """ Create a suitable Context from a plain dict and optionally an HttpRequest. """ + if context is not None and not isinstance(context, dict): + raise TypeError('context must be a dict rather than %s.' % context.__class__.__name__) if request is None: context = Context(context, **kwargs) else: diff --git a/django/views/csrf.py b/django/views/csrf.py index 493e112fbe..5e13e529fc 100644 --- a/django/views/csrf.py +++ b/django/views/csrf.py @@ -105,7 +105,7 @@ def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME): Default view used when request fails CSRF protection """ from django.middleware.csrf import REASON_NO_REFERER, REASON_NO_CSRF_COOKIE - c = Context({ + c = { 'title': _("Forbidden"), 'main': _("CSRF verification failed. Request aborted."), 'reason': reason, @@ -132,13 +132,14 @@ def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME): 'DEBUG': settings.DEBUG, 'docs_version': get_docs_version(), 'more': _("More information is available with DEBUG=True."), - }) + } try: t = loader.get_template(template_name) except TemplateDoesNotExist: if template_name == CSRF_FAILURE_TEMPLATE_NAME: # If the default template doesn't exist, use the string template. t = Engine().from_string(CSRF_FAILURE_TEMPLATE) + c = Context(c) else: # Raise if a developer-specified template doesn't exist. raise diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt index f894c261f9..0bf77e6e2d 100644 --- a/docs/releases/1.11.txt +++ b/docs/releases/1.11.txt @@ -575,6 +575,15 @@ Some undocumented classes in ``django.forms.widgets`` are removed: The ``Widget.format_output()`` method is removed. Use a custom widget template instead. +``django.Template.render()`` prohibits non-dict context +------------------------------------------------------- + +For compatibility with multiple template engines, ``django.Template.render()`` +must receive a dictionary of context rather than ``Context`` or +``RequestContext``. If you were passing either of the two classes, pass a +dictionary instead -- doing so is backwards-compatible with older versions of +Django. + Miscellaneous ------------- diff --git a/tests/template_backends/test_django.py b/tests/template_backends/test_django.py index 41eaff0c6d..567537f7a2 100644 --- a/tests/template_backends/test_django.py +++ b/tests/template_backends/test_django.py @@ -1,6 +1,6 @@ from template_tests.test_response import test_processor_name -from django.template import EngineHandler +from django.template import Context, EngineHandler, RequestContext from django.template.backends.django import DjangoTemplates from django.template.library import InvalidTemplateLibrary from django.test import RequestFactory, override_settings @@ -35,6 +35,24 @@ class DjangoTemplatesTests(TemplateStringsTests): content = template.render({'processors': 'no'}, request) self.assertEqual(content, 'no') + def test_render_requires_dict(self): + """django.Template.render() requires a dict.""" + engine = DjangoTemplates({ + 'DIRS': [], + 'APP_DIRS': False, + 'NAME': 'django', + 'OPTIONS': {}, + }) + template = engine.from_string('') + context = Context() + request_context = RequestContext(RequestFactory().get('/'), {}) + msg = 'context must be a dict rather than Context.' + with self.assertRaisesMessage(TypeError, msg): + template.render(context) + msg = 'context must be a dict rather than RequestContext.' + with self.assertRaisesMessage(TypeError, msg): + template.render(request_context) + @override_settings(INSTALLED_APPS=['template_backends.apps.good']) def test_templatetag_discovery(self): engine = DjangoTemplates({