¿Cómo establecer un valor de una variable dentro de un código de plantilla?

216

Digamos que tengo una plantilla

<html>
<div>Hello {{name}}!</div>
</html>

Mientras lo prueba, sería útil definir el valor de la variable sin tocar el código de Python que invoca esta plantilla. Entonces estoy buscando algo como esto

{% set name="World" %}     
<html>
<div>Hello {{name}}!</div>
</html>

¿Existe algo así en Django?

Alexis
fuente

Respuestas:

327

Puedes usar la withetiqueta de plantilla.

{% with name="World" %}     
<html>
<div>Hello {{name}}!</div>
</html>
{% endwith %}
Juan
fuente
35
pero ¿puedes cambiar el valor de la variable en con?
David 天宇 Wong
2
Parece que no puede declarar un contenedor (he intentado lista y tupla) en una cláusula con
Vladislav Ivanishin
Si necesita declarar una lista, use make_list. docs.djangoproject.com/en/1.9/ref/templates/builtins/#make-list
MrValdez
3
Jinja dice que es {% set myvar = value%} ¿por qué no funciona en django?
holms
3
@holms Debido a que Django no usa Jinja :-) docs.djangoproject.com/en/1.7/topics/templates
eliminado
50

Crea una etiqueta de plantilla:

La aplicación debe contener un templatetagsdirectorio, al mismo nivel que models.py, views.pyetc. Si aún no existe, créelo; no olvide el __init__.pyarchivo para asegurarse de que el directorio se trate como un paquete de Python.

Cree un archivo denominado define_action.pydentro del directorio templatetags con el siguiente código:

from django import template
register = template.Library()

@register.simple_tag
def define(val=None):
  return val

Nota: El servidor de desarrollo no se reiniciará automáticamente. Después de agregar el templatetagsmódulo, deberá reiniciar su servidor antes de poder usar las etiquetas o los filtros en las plantillas.


Luego, en su plantilla, puede asignar valores al contexto de esta manera:

{% load define_action %}
{% if item %}

   {% define "Edit" as action %}

{% else %}

   {% define "Create" as action %}

{% endif %}


Would you like to {{action}} this item?
Mods Vs Rockers
fuente
2
en mi caso, después del bucle, esto devuelve el valor anterior :(
holms
77
En la última versión parece que puedes usar simple_tag en lugar de task_tag (y funcionó para mí).
Katharine Osborne
El problema que obtuve con esta solución es que parece que no puede anular los valores.
Jakub Jabłoński
si desea utilizar esta técnica para establecer una lista en lugar de solo un valor, verifique esto: stackoverflow.com/a/34407158/2193235
msb
si está configurando la variable como un entero y quiere incrementarlo (por ejemplo), es necesario el uso add: {% define counter|add:1 as counter %}. Del mismo modo para otras operaciones.
msb
35

Una forma alternativa que no requiere que coloque todo en el bloque "con" es crear una etiqueta personalizada que agregue una nueva variable al contexto. Como en:

class SetVarNode(template.Node):
    def __init__(self, new_val, var_name):
        self.new_val = new_val
        self.var_name = var_name
    def render(self, context):
        context[self.var_name] = self.new_val
        return ''

import re
@register.tag
def setvar(parser,token):
    # This version uses a regular expression to parse tag contents.
    try:
        # Splitting by None == splitting by spaces.
        tag_name, arg = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents.split()[0]
    m = re.search(r'(.*?) as (\w+)', arg)
    if not m:
        raise template.TemplateSyntaxError, "%r tag had invalid arguments" % tag_name
    new_val, var_name = m.groups()
    if not (new_val[0] == new_val[-1] and new_val[0] in ('"', "'")):
        raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
    return SetVarNode(new_val[1:-1], var_name)

Esto te permitirá escribir algo como esto en tu plantilla:

{% setvar "a string" as new_template_var %}

Tenga en cuenta que la mayor parte de esto fue tomado de aquí

Karim
fuente
¿Qué hay de asignar variables a otras variables presentes en el contexto? Y en una nota diferente: permitir que las plantillas asignen arbitrariamente variables de contexto sin verificar si ya existen puede tener implicaciones de seguridad. Un enfoque más sensato en mi opinión sería verificar el contexto de la variable antes de intentar asignarla:
soze
if context.get (self.var_name): raise SuspiciousOperation ("Intento de asignar variable de plantilla ya presente en contexto")
soze
27

Hay trucos como el descrito por John; sin embargo, el lenguaje de plantilla de Django por diseño no admite el establecimiento de una variable (consulte el cuadro "Filosofía" en la documentación de Django para plantillas ).
Debido a esto, la forma recomendada de cambiar cualquier variable es tocar el código de Python.

robar
fuente
77
Gracias por la anotación. Desde la perspectiva de un diseñador, a veces es más fácil establecer rápidamente una variable para probar varios estados de una página mientras se diseña. No sugiere que esta práctica se use en un código en ejecución.
Alexis
2
la etiqueta "con" se acepta en django1.0. Parece que finalmente están modificando su filosofía :).
Evgeny
2
De hecho, la etiqueta "con" es solo para alias. Esto puede tener un gran impacto en el rendimiento (¡y también en la legibilidad!), Pero en realidad no está configurando una variable en términos de programación tradicional.
robar
12

La mejor solución para esto es escribir una costumbre assignment_tag. Esta solución es más limpia que usar una withetiqueta porque logra una separación muy clara entre la lógica y el estilo.

Comience creando un archivo de etiqueta de plantilla (por ejemplo appname/templatetags/hello_world.py):

from django import template

register = template.Library()

@register.assignment_tag
def get_addressee():
    return "World"

Ahora puede usar la get_addresseeetiqueta de plantilla en sus plantillas:

{% load hello_world %}

{% get_addressee as addressee %}

<html>
    <body>
        <h1>hello {{addressee}}</h1>
    </body>
</html>
entidad única
fuente
3
Para las personas que usan las versiones más nuevas de Django, ¡ahora se llama simple_tag! Ahorre tiempo para descubrir por qué "registrarse ..." no se reconoce en su código ...
kaya
11

Quizás el defaultfiltro de plantilla no era una opción en 2009 ...

<html>
<div>Hello {{name|default:"World"}}!</div>
</html>
John Mee
fuente
Debo decir que esto es lo que estaba buscando! También se puede utilizar con con : {% with state=form.state.value|default:other_context_variable %}en lugar de other_context_variableque también podemos utilizar cualquier 'string_value'así
Saurav Kumar
Pero lo imprimirá, y necesito guardarlo para usarlo más tarde
holms
4

Esta no es una buena idea en general. Haga toda la lógica en python y pase los datos a la plantilla para su visualización. La plantilla debe ser lo más simple posible para garantizar que quienes trabajan en el diseño puedan centrarse en el diseño en lugar de preocuparse por la lógica.

Para dar un ejemplo, si necesita información derivada dentro de una plantilla, es mejor ingresarla en una variable en el código de Python y luego pasarla a la plantilla.

Sarang
fuente
3

Utilice el con la declaración .

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

No puedo implicar el código en el primer párrafo de esta respuesta . Tal vez el lenguaje de la plantilla ha dejado de ser el formato anterior.

ramwin
fuente
2

En su plantilla puede hacer así:

{% jump_link as name %}
{% for obj in name %}
    <div>{{obj.helo}} - {{obj.how}}</div>
{% endfor %}

En sus plantillas de etiquetas puede agregar una etiqueta como esta:

@register.assignment_tag
def jump_link():
    listArr = []
    for i in range(5):
        listArr.append({"helo" : i,"how" : i})
    return listArr
Ashish Gupta
fuente