Login

Template tag: Extend with parameters

Author:
miracle2k
Posted:
October 17, 2007
Language:
Python
Version:
.96
Score:
7 (after 9 ratings)

Extended extends tag that supports passing parameters, which will be made available in the context of the extended template (and all the way up the hierarchy).

It wraps around the orginal extends tag, to avoid code duplication, and to not miss out on possible future django enhancements. Note: The current implementation will override variables passed from your view, too, so be careful.

Some of the argument parsing code is based on: http://www.djangosnippets.org/snippets/11/

Examples:

{% xextends "some.html" %}
{% xextends "some.html" with title="title1" %}
{% xextends "some.html" with title="title2"|capfirst %}
 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
from django import template
from django.template.loader_tags import do_extends
import tokenize
import StringIO

register = template.Library()

class XExtendsNode(template.Node):
    def __init__(self, node, kwargs):
        self.node = node
        self.kwargs = kwargs

    def render(self, context):
        # TODO: add the values to the bottom of the context stack instead?
        context.update(self.kwargs)
        try:
           return self.node.render(context)
        finally:
           context.pop()

def do_xextends(parser, token):
    bits = token.contents.split()
    kwargs = {}
    if 'with' in bits:
        pos = bits.index('with')
        argslist = bits[pos+1:]
        bits = bits[:pos]
        for i in argslist:
            try:
                a, b = i.split('=', 1); a = a.strip(); b = b.strip()
                keys = list(tokenize.generate_tokens(StringIO.StringIO(a).readline))
                if keys[0][0] == tokenize.NAME:
                    kwargs[str(a)] = parser.compile_filter(b)
                else: raise ValueError
            except ValueError:
                raise template.TemplateSyntaxError, "Argument syntax wrong: should be key=value"
        # before we are done, remove the argument part from the token contents,
        # or django's extends tag won't be able to handle it.
        # TODO: find a better solution that preserves the orginal token including whitespace etc.
        token.contents = " ".join(bits)

    # let the orginal do_extends parse the tag, and wrap the ExtendsNode
    return XExtendsNode(do_extends(parser, token), kwargs)

register.tag('xextends', do_xextends)

More like this

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

Comments

pakal (on November 7, 2020):

This tag is brillant, I've updated it to Django3.1 compatibility below (and fixed a bug with unresolved variables)

from django import template
from django.template.loader_tags import do_extends
import tokenize
from io import StringIO

register = template.Library()

class XExtendsNode(template.Node):
    def __init__(self, node, kwargs):
        self.node = node
        self.kwargs = kwargs

    def render(self, context):
        # TODO: add the values to the bottom of the context stack instead?
        resolved_kwargs = {key: value.resolve(context) for (key, value) in self.kwargs.items()}
        context.update(resolved_kwargs)
        try:
           return self.node.render(context)
        finally:
           context.pop()

def do_xextends(parser, token):
    bits = token.contents.split()
    kwargs = {}
    if 'with' in bits:
        pos = bits.index('with')
        argslist = bits[pos+1:]
        bits = bits[:pos]
        for i in argslist:
            try:
                a, b = i.split('=', 1); a = a.strip(); b = b.strip()
                keys = list(tokenize.generate_tokens(StringIO(a).readline))
                if keys[0][0] == tokenize.NAME:
                    kwargs[a] = parser.compile_filter(b)
                else: raise ValueError
            except ValueError:
                raise template.TemplateSyntaxError("Argument syntax wrong: should be key=value")
        # before we are done, remove the argument part from the token contents,
        # or django's extends tag won't be able to handle it.
        # TODO: find a better solution that preserves the original token including whitespace etc.
        token.contents = " ".join(bits)

    # let the orginal do_extends parse the tag, and wrap the ExtendsNode
    xnode = XExtendsNode(do_extends(parser, token), kwargs)
    # Setup here due to backwards compatibility concerns with node
    xnode.node.token = token
    xnode.node.origin = parser.origin
    return xnode


register.tag('xextends', do_xextends)

#

Please login first before commenting.