By default extend tag don't cache parents template. This is extend tag with patch. Workaround for bug: http://code.djangoproject.com/ticket/6586
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | from django.template.loader_tags import *
register = Library()
class ExtendsNode(Node):
must_be_first = True
def __init__(self, nodelist, parent_name, parent_name_expr, template_dirs=None):
self.nodelist = nodelist
self.parent_name, self.parent_name_expr = parent_name, parent_name_expr
self.template_dirs = template_dirs
self.compiled_parent = None
def __repr__(self):
if self.parent_name_expr:
return "<ExtendsNode: extends %s>" % self.parent_name_expr.token
return '<ExtendsNode: extends "%s">' % self.parent_name
def get_parent(self, context):
if self.parent_name_expr:
self.parent_name = self.parent_name_expr.resolve(context)
parent = self.parent_name
if not parent:
error_msg = "Invalid template name in 'extends' tag: %r." % parent
if self.parent_name_expr:
error_msg += " Got this from the '%s' variable." % self.parent_name_expr.token
raise TemplateSyntaxError, error_msg
if hasattr(parent, 'render'):
return parent # parent is a Template object
try:
source, origin = find_template_source(parent, self.template_dirs)
except TemplateDoesNotExist:
raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
else:
return get_template_from_string(source, origin, parent)
def process_parent( self, context ):
compiled_parent = self.get_parent(context)
pos = 0
while isinstance(compiled_parent.nodelist[pos], TextNode):
pos += 1
parent_is_child = isinstance(compiled_parent.nodelist[pos], ExtendsNode)
parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
for block_node in self.nodelist.get_nodes_by_type(BlockNode):
try:
parent_block = parent_blocks[block_node.name]
except KeyError:
if parent_is_child:
compiled_parent.nodelist[pos].nodelist.append(block_node)
else:
parent_block.parent = block_node.parent
parent_block.add_parent(parent_block.nodelist)
parent_block.nodelist = block_node.nodelist
return compiled_parent
def render(self, context):
if self.compiled_parent:
compiled_parent = self.compiled_parent
else:
compiled_parent = self.process_parent(context)
# cache it, if static
if self.parent_name:
self.compiled_parent = compiled_parent
return compiled_parent.render(context)
@register.tag
def extends(parser, token):
bits = token.contents.split()
if len(bits) != 2:
raise TemplateSyntaxError, "'%s' takes one argument" % bits[0]
parent_name, parent_name_expr = None, None
if bits[1][0] in ('"', "'") and bits[1][-1] == bits[1][0]:
parent_name = bits[1][1:-1]
else:
parent_name_expr = parser.compile_filter(bits[1])
nodelist = parser.parse()
if nodelist.get_nodes_by_type(ExtendsNode):
raise TemplateSyntaxError, "'%s' cannot appear more than once in the same template" % bits[0]
return ExtendsNode(nodelist, parent_name, parent_name_expr)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 9 months ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 9 months, 1 week ago
- Serializer factory with Django Rest Framework by julio 1 year, 4 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 4 months ago
- Help text hyperlinks by sa2812 1 year, 5 months ago
Comments
Render method for extends tag is called exactly once per template ( because only one extends tag can exist in template), so template processing is called exactly once. So your code will always call process_parent. No speed gain here.
#
Here is speed gain. In original extend function from django, it does not remember parsed parent file, so every request there is parser called. It doesn't work if you use render_to_response, becouse this function does not remember parsed tree.
Using my extends, you have about 10-20% faster template rendering. Realy.
#
Please login first before commenting.