2009-09-29 32 views
15

He creado una etiqueta de inclusión; sin embargo, me gustaría poder hacer que la plantilla sea opcionalmente configurable. No parece haber soporte para esto, así que me gustaría ver cómo lo hizo la gente, tal vez un método de búsqueda en el directorio de plantillas primero para un nombre de plantilla específico y luego volver a la plantilla predeterminada.Etiqueta de inclusión de Django con plantilla configurable

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

¿Qué intentas conseguir que '{% include my_template%}' no pueda? –

+0

Necesito agregar algunas variables al contexto con una etiqueta personalizada. Parece que tendré que escribir la etiqueta por el camino largo. Gracias. – meppum

Respuesta

4

El inclusion_tag decorador es sólo un atajo - se entiende como una forma sencilla de hacer una plantilla específica con un contexto específico. Tan pronto como quieras moverte fuera de eso, ya no podrá ayudarte. Pero eso solo significa que tendrá que escribir la etiqueta por mucho tiempo, como se explica en la documentación, y pasar la plantilla que desea como parámetro.

3

Tuve que hacer algo como esto para un proyecto y como necesitábamos más de uno de este tipo de etiqueta de inclusión, hice un decorador basado en django inclusion_tag decorator. Este es el código:

# -*- 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 

Debe devolver una tupla con la plantilla (o lista de plantillas) y el contexto dict. Tenga en cuenta que usted tiene que pasar el registro (ejemplo Biblioteca) en la llamada decorador:

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

espero que esto ayude

+0

¿Alguna idea de cómo actualizar esto para django 1.4? El generic_tag_compiler ahora necesita argumentos token y analizador – Gattster

28

utilizo simple_tag cuando necesito hacer eso:

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

Este post salvar mi vida: http://djangosnippets.org/snippets/1329/

la clave es añadir a la "plantilla de prueba":

{% extends template %} 
+0

¡Este es un gran consejo! Mejor aún, '@ register.inclusion_tag' puede tomar una instancia' Template' (además de una ruta), por lo que podría hacer algo como 'dummy = Template (" "" {% extends template%} "" ")', luego '@ register.inclusion_tag (dummy, takes_context = True)'. '' ' – Emil

0

Una solución podría ser una inclusion_tag normal que pase el nombre de la plantilla dinámica al context.

De esta manera:

# 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 

Y la plantilla:

<!-- include_tag.html --> 

{% include dynamic_template %} 

Los trucos aquí es, cuando llamo {% tag_manager %}, que incluye que a su vez incluye la plantilla devuelto por resolve_template() (no incluido para ser breve).

Espero que esto ayude ...

Cuestiones relacionadas