oliverpool
oliverpool

Reputation: 1671

Define custom django template tag on the fly

Is there a way in django to declare a custom template tag "on the fly"?

For example, if I have a page that renders an a tree structure and for my tag to work, it needs the root and the leaf. Since I now that I will use this tag only with this root (on the page), is there a way to create the template once I know which root will be used?

In my templates, I currently use:

{% render_leaf root leaf %}

I would like to create the tag "on the fly" (just after fetching the root), so that the root is now a local variable of the tag function, and I can simply call: {% render_leaf leaf %}

Upvotes: 0

Views: 242

Answers (2)

chrisv
chrisv

Reputation: 1481

Just in case anyone needs it, it's actually quite simple if you look at the source for Django's own {% load %} tag:

Approach

  1. define a static tag, e.g. {% import_dynamic_tags %}
  2. the parser function for this tag gives you access to the parser instance, which offers an add_library() method
  3. the argument for add_library is simply a new instance of django.template.base.Library
  4. at the new instance of Library, just call tag() or filter() to create dynamic templatetags and filters

Example

This code must be placed inside a regular template library, e.g. myapp.templatetags.dynamic_tags:

from django.template.base import Node, Library

register = template.Library()

class DummyNode(Node):
    """ 
    empty DummyNode, required since a parser function 
    must return a Node instance 
    """
    def render(self, context):
        return ''

@register.tag
def import_dynamic_tags(parser, token):
    # create a new template library
    lib = Library()

    # create an "uppercase" filter dynamically. Library.filter() 
    # expects a name, a filter function and optional flags like takes_context
    lib.filter('uppercase', lambda x: x.upper(), )

    # create a custom "{% foo %}"  templatetag. Library.tag() 
    # expects a name and a compiler function (the function you would normally
    # decorate with @register_tag)
    lib.tag('foo', foo_func)

    # finally, tell the parser about our newly created library 
    parser.add_library(lib)

    # filter functions MUST return a node, so just return DummyNode which
    # does nothing at render time
    return DummyNode()

Upvotes: 0

Sean Azlin
Sean Azlin

Reputation: 916

It would be far easier to move the dynamic part of the solution into your view (as mentioned in comments), and pass the correct root and leaves in the template's context. Doing this should then make the template really straight forward.

Upvotes: 1

Related Questions