Fixed #24694 -- Added support for context_processors to Jinja2 backend.
This commit is contained in:
parent
222e1334bf
commit
52a991d976
|
@ -8,6 +8,7 @@ import jinja2
|
|||
from django.conf import settings
|
||||
from django.template import TemplateDoesNotExist, TemplateSyntaxError
|
||||
from django.utils import six
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.module_loading import import_string
|
||||
|
||||
from .base import BaseEngine
|
||||
|
@ -23,6 +24,8 @@ class Jinja2(BaseEngine):
|
|||
options = params.pop('OPTIONS').copy()
|
||||
super(Jinja2, self).__init__(params)
|
||||
|
||||
self.context_processors = options.pop('context_processors', [])
|
||||
|
||||
environment = options.pop('environment', 'jinja2.Environment')
|
||||
environment_cls = import_string(environment)
|
||||
|
||||
|
@ -36,11 +39,11 @@ class Jinja2(BaseEngine):
|
|||
self.env = environment_cls(**options)
|
||||
|
||||
def from_string(self, template_code):
|
||||
return Template(self.env.from_string(template_code))
|
||||
return Template(self.env.from_string(template_code), self)
|
||||
|
||||
def get_template(self, template_name):
|
||||
try:
|
||||
return Template(self.env.get_template(template_name))
|
||||
return Template(self.env.get_template(template_name), self)
|
||||
except jinja2.TemplateNotFound as exc:
|
||||
six.reraise(
|
||||
TemplateDoesNotExist,
|
||||
|
@ -52,11 +55,16 @@ class Jinja2(BaseEngine):
|
|||
new.template_debug = get_exception_info(exc)
|
||||
six.reraise(TemplateSyntaxError, new, sys.exc_info()[2])
|
||||
|
||||
@cached_property
|
||||
def template_context_processors(self):
|
||||
return [import_string(path) for path in self.context_processors]
|
||||
|
||||
|
||||
class Template(object):
|
||||
|
||||
def __init__(self, template):
|
||||
def __init__(self, template, backend):
|
||||
self.template = template
|
||||
self.backend = backend
|
||||
self.origin = Origin(
|
||||
name=template.filename, template_name=template.name,
|
||||
)
|
||||
|
@ -68,6 +76,8 @@ class Template(object):
|
|||
context['request'] = request
|
||||
context['csrf_input'] = csrf_input_lazy(request)
|
||||
context['csrf_token'] = csrf_token_lazy(request)
|
||||
for context_processor in self.backend.template_context_processors:
|
||||
context.update(context_processor(request))
|
||||
return self.template.render(context)
|
||||
|
||||
|
||||
|
|
|
@ -220,6 +220,10 @@ Templates
|
|||
|
||||
* :meth:`~django.utils.safestring.mark_safe` can now be used as a decorator.
|
||||
|
||||
* The :class:`~django.template.backends.jinja2.Jinja2` template backend now
|
||||
supports context processors by setting the ``'context_processors'`` option in
|
||||
:setting:`OPTIONS <TEMPLATES-OPTIONS>`.
|
||||
|
||||
Tests
|
||||
~~~~~
|
||||
|
||||
|
|
|
@ -398,13 +398,27 @@ adds defaults that differ from Jinja2's for a few options:
|
|||
* ``'auto_reload'``: ``settings.DEBUG``
|
||||
* ``'undefined'``: ``DebugUndefined if settings.DEBUG else Undefined``
|
||||
|
||||
``Jinja2`` engines also accept the following :setting:`OPTIONS
|
||||
<TEMPLATES-OPTIONS>`:
|
||||
|
||||
* ``'context_processors'``: a list of dotted Python paths to callables that
|
||||
are used to populate the context when a template is rendered with a request.
|
||||
These callables take a request object as their argument and return a
|
||||
:class:`dict` of items to be merged into the context.
|
||||
|
||||
It defaults to an empty list.
|
||||
|
||||
.. versionadded:: 1.11
|
||||
|
||||
The ``'context_processors'`` option was added.
|
||||
|
||||
The default configuration is purposefully kept to a minimum. If a template is
|
||||
rendered with a request (e.g. when using :py:func:`~django.shortcuts.render`),
|
||||
the ``Jinja2`` backend adds the globals ``request``, ``csrf_input``, and
|
||||
``csrf_token`` to the context. Apart from that, this backend doesn't create a
|
||||
Django-flavored environment. It doesn't know about Django context processors,
|
||||
filters, and tags. In order to use Django-specific APIs, you must configure
|
||||
them into the environment.
|
||||
Django-flavored environment. It doesn't know about Django filters and tags.
|
||||
In order to use Django-specific APIs, you must configure them into the
|
||||
environment.
|
||||
|
||||
For example, you can create ``myproject/jinja2.py`` with this content::
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ from __future__ import absolute_import
|
|||
from unittest import skipIf
|
||||
|
||||
from django.template import TemplateSyntaxError
|
||||
from django.test import RequestFactory
|
||||
|
||||
from .test_dummy import TemplateStringsTests
|
||||
|
||||
|
@ -22,7 +23,12 @@ class Jinja2Tests(TemplateStringsTests):
|
|||
|
||||
engine_class = Jinja2
|
||||
backend_name = 'jinja2'
|
||||
options = {'keep_trailing_newline': True}
|
||||
options = {
|
||||
'keep_trailing_newline': True,
|
||||
'context_processors': [
|
||||
'django.template.context_processors.static',
|
||||
],
|
||||
}
|
||||
|
||||
def test_origin(self):
|
||||
template = self.engine.get_template('template_backends/hello.html')
|
||||
|
@ -74,3 +80,12 @@ class Jinja2Tests(TemplateStringsTests):
|
|||
self.assertEqual(len(debug['source_lines']), 21)
|
||||
self.assertTrue(debug['name'].endswith('syntax_error2.html'))
|
||||
self.assertIn('message', debug)
|
||||
|
||||
def test_context_processors(self):
|
||||
request = RequestFactory().get('/')
|
||||
template = self.engine.from_string('Static URL: {{ STATIC_URL }}')
|
||||
content = template.render(request=request)
|
||||
self.assertEqual(content, 'Static URL: /static/')
|
||||
with self.settings(STATIC_URL='/s/'):
|
||||
content = template.render(request=request)
|
||||
self.assertEqual(content, 'Static URL: /s/')
|
||||
|
|
Loading…
Reference in New Issue