Fixed #27258 -- Prohibited django.Template.render() with non-dict context.

Thanks Shivang Bharadwaj for the initial patch.
This commit is contained in:
Shivang Bharadwaj 2016-12-29 02:33:20 +05:30 committed by Tim Graham
parent 4e89082f31
commit 6a74950513
4 changed files with 33 additions and 3 deletions

View File

@ -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:

View File

@ -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

View File

@ -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
-------------

View File

@ -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({