mirror of https://github.com/django/django.git
Fixed #23516 -- Added caching of include tag Template objects
This also speeds up for loops that render the same template multiple times.
This commit is contained in:
parent
2a7c59cd88
commit
a391b17ad2
|
@ -171,6 +171,8 @@ class ExtendsNode(Node):
|
||||||
|
|
||||||
|
|
||||||
class IncludeNode(Node):
|
class IncludeNode(Node):
|
||||||
|
context_key = '__include_context'
|
||||||
|
|
||||||
def __init__(self, template, *args, **kwargs):
|
def __init__(self, template, *args, **kwargs):
|
||||||
self.template = template
|
self.template = template
|
||||||
self.extra_context = kwargs.pop('extra_context', {})
|
self.extra_context = kwargs.pop('extra_context', {})
|
||||||
|
@ -178,12 +180,22 @@ class IncludeNode(Node):
|
||||||
super(IncludeNode, self).__init__(*args, **kwargs)
|
super(IncludeNode, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
|
"""
|
||||||
|
Render the specified template and context. Cache the template object
|
||||||
|
in render_context to avoid reparsing and loading when used in a for
|
||||||
|
loop.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
template = self.template.resolve(context)
|
template = self.template.resolve(context)
|
||||||
# Does this quack like a Template?
|
# Does this quack like a Template?
|
||||||
if not callable(getattr(template, 'render', None)):
|
if not callable(getattr(template, 'render', None)):
|
||||||
# If not, we'll try get_template
|
# If not, we'll try our cache, and get_template()
|
||||||
template = context.template.engine.get_template(template)
|
template_name = template
|
||||||
|
cache = context.render_context.setdefault(self.context_key, {})
|
||||||
|
template = cache.get(template_name)
|
||||||
|
if template is None:
|
||||||
|
template = context.template.engine.get_template(template_name)
|
||||||
|
cache[template_name] = template
|
||||||
values = {
|
values = {
|
||||||
name: var.resolve(context)
|
name: var.resolve(context)
|
||||||
for name, var in six.iteritems(self.extra_context)
|
for name, var in six.iteritems(self.extra_context)
|
||||||
|
|
|
@ -314,6 +314,9 @@ Templates
|
||||||
* The ``timesince`` and ``timeuntil`` filters were improved to deal with leap
|
* The ``timesince`` and ``timeuntil`` filters were improved to deal with leap
|
||||||
years when given large time spans.
|
years when given large time spans.
|
||||||
|
|
||||||
|
* The ``include`` tag now caches parsed templates objects during template
|
||||||
|
rendering, speeding up reuse in places such as for loops.
|
||||||
|
|
||||||
Requests and Responses
|
Requests and Responses
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -196,3 +196,17 @@ class IfChangedTests(SimpleTestCase):
|
||||||
template = self.engine.from_string('{% ifchanged %}{% cycle "1st time" "2nd time" %}{% endifchanged %}')
|
template = self.engine.from_string('{% ifchanged %}{% cycle "1st time" "2nd time" %}{% endifchanged %}')
|
||||||
output = template.render(Context({}))
|
output = template.render(Context({}))
|
||||||
self.assertEqual(output, '1st time')
|
self.assertEqual(output, '1st time')
|
||||||
|
|
||||||
|
def test_include(self):
|
||||||
|
"""
|
||||||
|
#23516 -- This works as a regression test only if the cached loader
|
||||||
|
isn't used. Hence we don't use the @setup decorator.
|
||||||
|
"""
|
||||||
|
engine = Engine(loaders=[
|
||||||
|
('django.template.loaders.locmem.Loader', {
|
||||||
|
'template': '{% for x in vars %}{% include "include" %}{% endfor %}',
|
||||||
|
'include': '{% ifchanged %}{{ x }}{% endifchanged %}',
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
output = engine.render_to_string('template', dict(vars=[1, 1, 2, 2, 3, 3]))
|
||||||
|
self.assertEqual(output, "123")
|
||||||
|
|
Loading…
Reference in New Issue