Login

Partial templates, combine with and include

Author:
koblas
Posted:
April 16, 2010
Language:
Python
Version:
1.1
Tags:
template templates partial with include partials
Score:
3 (after 3 ratings)

This snippet adds simple partial support to your templates. You can pass data to the partial, and use it as you would in a regular template. It is different from Django's {% include %}, because it allows you to pass a custom variable (context), instead of reusing the same context for the included template. This decouples the templates from each other and allows for their greater reuse.

The attached code needs to go into templatetags folder underneath your project. The usage is pretty simple - {% load ... %} the tag library, and use {% partial_template template-name data %} in your template. This will result in template passed as template-name to be loaded from your regular template folders.

The variables are passed in a with compatiable syntax, eg. VAR as NAME and VAR as NAME No limitations on the number of variables passed.

 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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
from django.template import Library, Variable, Node
from django.template.loader import get_template
from django.template import TemplateSyntaxError

register = Library()

"""
Combines 'with' and 'include' to something useful:

For example: 
  {% partial "table_list.html" hot as urls and 1 as listid and "Hot items" as title %}

Will include the "table_list.html" file -- using the same include rules a django
and have the 'listid', 'urls', and 'title' variables set in the include context.
"""

class PartialNode(Node):
    def __init__(self, path, is_constant, params):
        self.params = params
        self.tmpl   = None
        self.vtmpl  = None

        if is_constant :
            try :
                self.tmpl = get_template(path)
            except : 
                if settings.TEMPLATE_DEBUG :
                    raise
        else :
            self.vtmpl = Variable(path)
    
    def render(self, context):
        tmpl = None

        if self.tmpl :
            tmpl = self.tmpl
        elif self.vtmpl :
            try :
                t = self.vtmpl.resolve(context)
                tmpl = get_template(t)
            except TemplateSyntaxError, e :
                if settings.TEMPLATE_DEBUG :
                    raise
                return ''
            except :
                return ''   # Fail silently for invalid included templates.

        if not tmpl :
            return ''

        update = {}
        for k, v in self.params.items() :
            val = v.resolve(context)
            print "V = ", v, val
            update[k] = val

        context.push()
        context.update(update)
        output = tmpl.render(context)
        context.pop()
        return output

def render_partial(parser, token):
    params = {}

    bits = token.split_contents()
    if len(bits) < 2 :
        raise TemplateSyntaxError("%r tag takes at least one argument: the name of the template to be included" % bits[0])
    try:
        path = bits[1]

        state = 0
        val   = None
        for p in bits[2:] :
            if state == 0 :
                val = p
                state += 1
            elif state == 1 :
                if p.lower() != 'as' :
                    raise TemplateSyntaxError("%r expected format is 'value as name'" % bits[0])
                state += 1
            elif state == 2 :
                params[p] = Variable(val)
                state += 1
            elif state == 3 :
                if p.lower() != 'and' :
                    raise TemplateSyntaxError("%r expected format is 'value as name and'" % bits[0])
                state = 0 
            
    except ValueError:
        raise template.TemplateSyntaxError, '%r tag requires at least a single argument and no spaces in name:value list' % parts[0]

    if path[0] in ('"', "'") and path[0] == path[-1] :
        return PartialNode(path[1:-1], True, params)
    return PartialNode(path, False, params)

render_partial = register.tag('partial', render_partial)

More like this

  1. "Partial Templates" - an alternative to "include" by vigrid 6 years, 1 month ago
  2. partial tag by bl4th3rsk1t3 5 years, 9 months ago
  3. Partial Tag by mnbayazit 4 years, 8 months ago
  4. render_partial by hachaboob 6 years, 6 months ago
  5. Repeat blocks with new context / simple Jinja-like macro system by miracle2k 7 years, 8 months ago

Comments

Please login first before commenting.