Login

extend tag with cache

Author:
fredd4
Posted:
February 20, 2008
Language:
Python
Version:
.96
Score:
-2 (after 2 ratings)

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

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 1 week ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 5 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

forgems (on February 21, 2008):

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.

#

fredd4 (on December 2, 2008):

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.