Django inclusion tag with configurable template

前端 未结 5 915
不知归路
不知归路 2020-12-13 14:42

I\'ve created an inclusion tag, however I\'d like to be able to make the template optionally configurable. There doesn\'t seem to be support for this out of the box, so I\'d

相关标签:
5条回答
  • 2020-12-13 15:20

    A solution could be a regular inclusion_tag which pass dynamic template name to context.

    Like this :

    # templatetags/tags.py
    
    @register.inclusion_tag('include_tag.html', takes_context=True)
    def tag_manager(context):
        context.update({
            'dynamic_template': resolve_template(context),
        })
        return context
    

    And the template:

    <!-- include_tag.html -->
    
    {% include dynamic_template %}
    

    The tricks here is, when I call {% tag_manager %}, it includes include_tag.html which in turn includes the template returned by resolve_template() (not included for brevity).

    Hope this helps...

    0 讨论(0)
  • 2020-12-13 15:26

    This post save my life: http://djangosnippets.org/snippets/1329/

    The key is add to the "dummy template":

    {% extends template %}
    
    0 讨论(0)
  • 2020-12-13 15:37

    The inclusion_tag decorator is just a shortcut - it's meant as a simple way of rendering a specific template with a specific context. As soon as you want to move outside of that, it can no longer help you. But that just means you'll have to write the tag the long way, as explained in the documentation, and pass the template you want as a parameter.

    0 讨论(0)
  • 2020-12-13 15:37

    I use simple_tag when i need to do that:

    from django.template import Library, loader, Context
    
    @register.simple_tag(takes_context=True)
    def my_tag(context, template_name):
    
        var1 = ...
    
        t = loader.get_template(template_name)
        return t.render(Context({
            'var1': var1,
            ...
        }))
    
    0 讨论(0)
  • 2020-12-13 15:37

    I had to do something like this for a project and since we needed more than one of this kind of inclusion tag I made a decorator based on django inclusion_tag decorator. This is the code:

    # -*- coding: utf-8 -*-
    from django import template
    from inspect import getargspec
    from django.template.context import Context
    from django.template import Node, generic_tag_compiler, Variable
    from django.utils.functional import curry
    
    
    def inclusion_tag(register, context_class=Context, takes_context=False):
        def dec(func):
            params, xx, xxx, defaults = getargspec(func)
            if takes_context:
                if params[0] == 'context':
                    params = params[1:]
                else:
                    raise TemplateSyntaxError("Any tag function decorated with takes_context=True must have a first argument of 'context'")
    
            class InclusionNode(Node):
                def __init__(self, vars_to_resolve):
                    self.vars_to_resolve = map(Variable, vars_to_resolve)
    
                def render(self, context):
                    resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
                    if takes_context:
                        args = [context] + resolved_vars
                    else:
                        args = resolved_vars
    
                    file_name, extra_context = func(*args)
    
                    from django.template.loader import get_template, select_template
                    if not isinstance(file_name, basestring) and is_iterable(file_name):
                        t = select_template(file_name)
                    else:
                        t = get_template(file_name)
                    self.nodelist = t.nodelist
                    new_context = context_class(extra_context, autoescape=context.autoescape)
                    # Copy across the CSRF token, if present, because inclusion
                    # tags are often used for forms, and we need instructions
                    # for using CSRF protection to be as simple as possible.
                    csrf_token = context.get('csrf_token', None)
                    if csrf_token is not None:
                        new_context['csrf_token'] = csrf_token
                    return self.nodelist.render(new_context)
    
            compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, InclusionNode)
            compile_func.__doc__ = func.__doc__
            register.tag(getattr(func, "_decorated_function", func).__name__, compile_func)
            return func
        return dec
    

    You have to return a tuple with the template (or template list) and the context dict. Note that you have to pass the register (Library instance) in the decorator call:

    from somewhere import inclusion_tag
    @inclusion_tag(register)
    def display_formset(formset):
        template_name = FORMSET_TEMPLATES.get(formset.model,
            'includes/inline_formset.html')
        return (template_name, {'formset': formset})
    

    Hope this helps

    0 讨论(0)
提交回复
热议问题