Wie setze ich einen Wert einer Variablen in einem Vorlagencode?


216

Angenommen, ich habe eine Vorlage

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

Während des Testens ist es hilfreich, den Wert der Variablen zu definieren, ohne den Python-Code zu berühren, der diese Vorlage aufruft. Also suche ich so etwas

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

Gibt es so etwas in Django?

Antworten:


327

Sie können das withVorlagen-Tag verwenden.

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

35
Aber können Sie den Wert der Variablen im with ändern?
David 天宇 Wong

2
Es scheint, dass Sie keinen Container (ich habe Liste und Tupel versucht) in einer with-Klausel
deklarieren können

Wenn Sie eine Liste deklarieren müssen, verwenden Sie make_list. docs.djangoproject.com/de/1.9/ref/templates/builtins/#make-list
MrValdez

3
Jinja sagt, es ist {% set myvar = value%}, warum es in Django nicht funktioniert?
Holms

3
@holms Weil Django Jinja nicht benutzt :-) docs.djangoproject.com/de/1.7/topics/templates
elimisteve

50

Erstellen Sie ein Vorlagen-Tag:

Die App sollte enthalten templatetagsVerzeichnis, auf dem gleichen Niveau wie models.py, views.pyusw. Wenn dies nicht bereits vorhanden ist , erstellen Sie es - nicht das vergisst __init__.pyDatei das Verzeichnis , um sicherzustellen , wird als ein Python - Paket behandelt.

Erstellen Sie eine Datei mit dem Namen define_action.pyinnerhalb des templatetags Verzeichnis mit dem folgenden Code:

from django import template
register = template.Library()

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

Hinweis: Der Entwicklungsserver wird nicht automatisch neu gestartet. Nach dem Hinzufügen des templatetagsModuls müssen Sie Ihren Server neu starten, bevor Sie die Tags oder Filter in Vorlagen verwenden können.


Dann können Sie in Ihrer Vorlage dem Kontext folgende Werte zuweisen:

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

   {% define "Edit" as action %}

{% else %}

   {% define "Create" as action %}

{% endif %}


Would you like to {{action}} this item?

2
In meinem Fall nach der Schleife gibt dies den alten Wert zurück :(
Holms

7
In der neuesten Version scheint es, dass Sie simple_tag anstelle von assign_tag verwenden können (und es hat bei mir funktioniert).
Katharine Osborne

Das Problem bei dieser Lösung ist, dass Sie anscheinend keine Werte überschreiben können.
Jakub Jabłoński

Wenn Sie diese Technik verwenden möchten, um eine Liste anstelle eines Werts festzulegen
Folgendes

Wenn Sie die Variable als Ganzzahl festlegen und sie beispielsweise erhöhen möchten, müssen Sie Folgendes verwenden add: {% define counter|add:1 as counter %}. Ähnliches gilt für andere Operationen.
msb

35

Eine alternative Möglichkeit, bei der Sie nicht alles in den Block "with" einfügen müssen, besteht darin, ein benutzerdefiniertes Tag zu erstellen, das dem Kontext eine neue Variable hinzufügt. Wie in:

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)

Auf diese Weise können Sie Folgendes in Ihre Vorlage schreiben:

{% setvar "a string" as new_template_var %}

Beachten Sie, dass das meiste davon von hier übernommen wurde


Wie wäre es mit der Zuweisung von Variablen zu anderen im Kontext vorhandenen Variablen? Und noch etwas: Das Zulassen, dass Vorlagen Kontextvariablen willkürlich zuweisen können, ohne zu prüfen, ob sie bereits vorhanden sind, kann Auswirkungen auf die Sicherheit haben. Ein vernünftigerer Ansatz wäre meiner Meinung nach, den Kontext für die Variable zu überprüfen, bevor Sie versuchen, sie zuzuweisen:
Soze

if context.get (self.var_name): Erhöhen Sie SuspiciousOperation ("Versuch, eine Variable aus einer Vorlage zuzuweisen, die bereits im Kontext vorhanden ist")
Soze

27

Es gibt Tricks wie den von John beschriebenen; Die Vorlagensprache von Django unterstützt jedoch nicht das Festlegen einer Variablen ( Vorlagen finden Sie im Feld "Philosophie" in der Django-Dokumentation ).
Aus diesem Grund , die empfohlene Methode , eine Variable zu ändern , ist die Python - Code über berühren.


7
Danke für den Zeiger. Aus Sicht eines Designers ist es manchmal einfacher, eine Variable schnell festzulegen, um verschiedene Zustände einer Seite beim Entwerfen zu testen. Es wird nicht empfohlen, diese Vorgehensweise in einem laufenden Code zu verwenden.
Alexis

2
Das "with" -Tag wird in django1.0 akzeptiert. Sieht also so aus, als würden sie endlich ihre Philosophie ändern :).
Evgeny

2
Tatsächlich ist das "with" -Tag nur für Aliase. Dies kann einen großen Einfluss auf die Leistung (und auch auf die Lesbarkeit!) Haben, setzt jedoch in herkömmlichen Programmierbegriffen nicht wirklich eine Variable.
Rob

12

Die beste Lösung hierfür ist das Schreiben eines benutzerdefinierten assignment_tag. Diese Lösung ist sauberer als die Verwendung eines withTags, da eine sehr klare Trennung zwischen Logik und Stil erreicht wird.

Erstellen Sie zunächst eine Vorlagen-Tag-Datei (z. B. appname/templatetags/hello_world.py):

from django import template

register = template.Library()

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

Jetzt können Sie das get_addresseeVorlagen-Tag in Ihren Vorlagen verwenden:

{% load hello_world %}

{% get_addressee as addressee %}

<html>
    <body>
        <h1>hello {{addressee}}</h1>
    </body>
</html>

3
Für Leute, die die neueren Django-Versionen verwenden, heißt es jetzt simple_tag! Sparen Sie sich die Zeit, um herauszufinden, warum "register .." in Ihrem Code nicht erkannt wird ...
kaya

11

Vielleicht war der defaultVorlagenfilter 2009 keine Option ...

<html>
<div>Hello {{name|default:"World"}}!</div>
</html>

Ich muss sagen, dass ich so gesucht habe! Es kann auch mit verwendet werden , werden mit : {% with state=form.state.value|default:other_context_variable %}statt other_context_variablewir auch alle können 'string_value'auch
Saurav Kumar

Aber es wird gedruckt, und ich muss es für die spätere Verwendung
speichern

4

Dies ist im Allgemeinen keine gute Idee. Führen Sie die gesamte Logik in Python aus und übergeben Sie die Daten zur Anzeige an die Vorlage. Die Vorlage sollte so einfach wie möglich sein, um sicherzustellen, dass sich diejenigen, die am Design arbeiten, auf das Design konzentrieren können, anstatt sich um die Logik zu kümmern.

Wenn Sie beispielsweise abgeleitete Informationen in einer Vorlage benötigen, ist es besser, diese in eine Variable im Python-Code zu übernehmen und sie dann an die Vorlage weiterzugeben.


3

Verwenden Sie die with-Anweisung .

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

Ich kann den Code im ersten Absatz dieser Antwort nicht implizieren . Möglicherweise hatte die Vorlagensprache das alte Format veraltet.


2

In Ihrer Vorlage können Sie Folgendes tun:

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

In Ihren Template-Tags können Sie ein Tag wie folgt hinzufügen:

@register.assignment_tag
def jump_link():
    listArr = []
    for i in range(5):
        listArr.append({"helo" : i,"how" : i})
    return listArr
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.