2011-10-17 25 views
8

Estoy implementando una aplicación de permisos personalizados en mi proyecto Django, y estoy perdido en cuanto a cómo implementar una etiqueta de plantilla personalizada que comprueba los permisos de un usuario conectado para una instancia de objeto específico y muestra una pieza de HTML basada en el resultado del cheque.if..else personalizado plantilla etiqueta

Lo que tenemos ahora es (pseudocódigo):

{% check_permission request.user "can_edit" on article %} 
    <form>...</form> 
{% endcheck %} 

('check_permission' es mi etiqueta de plantilla personalizada).

La etiqueta de plantilla toma el usuario, el permiso y la instancia del objeto y devuelve el HTML adjunto (el formulario). Esto actualmente funciona bien.

Lo que me gustaría hacer, sin embargo, es algo así como:

{% if check_permission request.user "can_edit" on article %} 
    <form>...</form> 
{% else %} 
    {{ article }} 
{% endif %} 

He leído sobre the assignment tag, pero mi miedo es que iba a contaminar el espacio de las variables de contexto con esto (lo que significa que podría sobrescribir anterior variables de contexto de permisos). En otras palabras, como las variables de contexto se están definiendo en diferentes niveles (la vista, el middleware en mi caso y ahora esta etiqueta de plantilla de asignación), me preocupa la capacidad de mantenimiento.

Respuesta

13

Puede usar filtros de plantilla dentro de sentencias if. Por lo que podría volver a escribir su etiqueta como un filtro:

{% if request.user|check_can_edit:article %} 

Tenga en cuenta que es difícil de pasar múltiples argumentos de diferentes tipos a un filtro, por lo que es probable que desee utilizar un filtro por el permiso, por encima de que he usado check_can_edit.

+0

Gracias, los filtros podrían ser una opción. Sin embargo, preveo diferentes permisos (no solo el CRUD básico en la instancia, sino algunos muy específicos), lo que significa que tendría que crear una cantidad igual de filtros de plantilla personalizados. Sin embargo, tal vez debería reconsiderar mi modelo de permisos personalizados. Si dice que es complicado pasar múltiples argumentos a un filtro, ¿quiere decir que es posible? Pensé que no era así, ¿podrías aclarar esto un poco? – LaundroMat

+1

Actualizar a futuros visitantes: creo que intentaré resolverlo con filtros encadenados (por ejemplo, '{{request.user | has_permission:" entries.entry.can_edit, "| has_permission_on: article}}'. El filtro de plantilla personalizada has_permission devuelve el usuario y el permiso requerido, has_permission_on toma estos valores, los compara con la variable del artículo y devuelve True o False. – LaundroMat

12

¡Definitivamente puede hacer eso si está dispuesto a escribir más líneas de código python para mejorar la legibilidad de su plantilla! :)

Necesita analizar el contenido de la etiqueta usted mismo, incluso los parámetros que toma y luego resolverlos, si desea usar variables en ellos.

La etiqueta implementado continuación se puede utilizar como esto:

{% load mytag %} 
{% mytag True %}Hi{% else %}Hey{% endmytag %} Bro 

O con una variable:

{% mytag myobject.myflag %}Hi{% else %}Hey{% endmytag %} Bro 

tanto, aquí está la forma en que lo hice:

from django.template import Library, Node, TemplateSyntaxError 

register = Library() 

@register.tag 
def mytag(parser, token): 
    # Separating the tag name from the "test" parameter. 
    try: 
     tag, test = token.contents.split() 
    except (ValueError, TypeError): 
     raise TemplateSyntaxError(
      "'%s' tag takes two parameters" % tag) 

    default_states = ['mytag', 'else'] 
    end_tag = 'endmytag' 

    # Place to store the states and their values 
    states = {} 

    # Let's iterate over our context and find our tokens 
    while token.contents != end_tag: 
     current = token.contents 
     states[current.split()[0]] = parser.parse(default_states + [end_tag]) 
     token = parser.next_token() 

    test_var = parser.compile_filter(test) 
    return MyNode(states, test_var) 


class MyNode(Node): 
    def __init__(self, states, test_var): 
     self.states = states 
     self.test_var = test_var 

    def render(self, context): 
     # Resolving variables passed by the user 
     test_var = self.test_name.resolve(context, True) 

     # Rendering the right state. You can add a function call, use a 
     # library or whatever here to decide if the value is true or false. 
     is_true = bool(test_var) 
     return self.states[is_true and 'myvar' or 'else'].render(context) 

Y Eso es. HTH.

+0

respuesta real aquí – snakesNbronies