2009-09-29 6 views
15

J'ai créé une balise d'inclusion, mais j'aimerais pouvoir rendre le gabarit facultatif. Il ne semble pas y avoir de support pour ce type de configuration, alors j'aimerais voir comment les gens ont fait cela - peut-être qu'une méthode recherche d'abord le répertoire des modèles pour un nom de modèle spécifique et retombe ensuite dans le modèle par défaut.Balise d'inclusion Django avec gabarit configurable

@register.inclusion_tag('foo.html', takes_context=True) 
+0

Qu'est-ce que vous essayez d'atteindre que '{% comprennent my_template%}' ne peut pas? –

+0

Je dois ajouter quelques variables au contexte avec une balise personnalisée. On dirait que je vais devoir écrire l'étiquette le long chemin. Merci. – meppum

Répondre

4

Le décorateur inclusion_tag est juste un raccourci - il est conçu comme un moyen simple de rendre un modèle spécifique à un contexte spécifique. Dès que vous voulez sortir de ça, ça ne peut plus vous aider. Mais cela signifie simplement que vous devrez écrire le tag le long chemin, comme expliqué dans la documentation, et passer le template que vous voulez en paramètre.

3

Je devais faire quelque chose comme ça pour un projet et comme nous avions besoin de plus d'un de ces tags d'inclusion, j'ai fait un décorateur basé sur le décorateur django inclusion_tag. Ceci est le 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 

Vous devez renvoyer un tuple avec le modèle (ou la liste de modèles) et le contexte. Notez que vous devez passer le registre (instance Library) dans l'appel décorateur:

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

Une idée de comment mettre à jour ceci pour django 1.4? Le generic_tag_compiler a maintenant besoin d'arguments de jeton et d'analyseur – Gattster

28

J'utilise simple_tag quand je dois faire:

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, 
     ... 
    })) 
7

Ce poste sauver ma vie: http://djangosnippets.org/snippets/1329/

la clé est d'ajouter au « modèle factice »:

{% extends template %} 
+0

Ceci est un bon conseil! Encore mieux, '@ register.inclusion_tag' peut prendre une instance' Template' (en plus d'un chemin), donc vous pouvez faire quelque chose comme 'dummy = Template (" "" {% extends template%} "" ")', then '@ register.inclusion_tag (dummy, takes_context = True)'. '' ' – Emil

0

Une solution peut être un inclusion_tag normal qui transmet le nom de modèle dynamique à context.

Comme ceci:

# 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 

Et le modèle:

<!-- include_tag.html --> 

{% include dynamic_template %} 

Les trucs ici est, quand je l'appelle {% tag_manager %}, il comprend qui comprend à son tour le modèle retourné par resolve_template() (non inclus pour la brièveté).

Hope this helps ...

Questions connexes