Jak ustawić wartość zmiennej w kodzie szablonu?


216

Powiedz, że mam szablon

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

Podczas testowania przydatne byłoby zdefiniowanie wartości zmiennej bez dotykania kodu python, który wywołuje ten szablon. Więc szukam czegoś takiego

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

Czy coś takiego istnieje w Django?

Odpowiedzi:


327

Możesz użyć withznacznika szablonu.

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

35
ale czy możesz zmienić wartość zmiennej za pomocą?
David 天宇 Wong

2
Wygląda na to, że nie można zadeklarować kontenera (próbowałem listy i krotki) w klauzuli z
Vladislav Ivanishin

Jeśli chcesz zadeklarować listę, użyj make_list. docs.djangoproject.com/en/1.9/ref/templates/builtins/#make-list
MrValdez

3
Jinja mówi, że {% set myvar = wartość%} dlaczego nie działa w Django?
holms

3
@holms Ponieważ Django nie używa Jinja :-) docs.djangoproject.com/en/1.7/topics/templates
elimisteve

50

Utwórz tag szablonu:

Aplikacja powinna zawierać templatetagskatalog, na tym samym poziomie jak models.py, views.pyitd Jeśli to nie istnieje, utwórz go - nie zapomnij o __init__.pypliku, aby zapewnić katalog jest traktowany jako pakiet Pythona.

Utwórz plik o nazwie define_action.pywewnątrz katalogu templatetags z następującym kodem:

from django import template
register = template.Library()

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

Uwaga: Serwer programistyczny nie uruchomi się automatycznie. Po dodaniu templatetagsmodułu konieczne będzie zrestartowanie serwera przed użyciem tagów lub filtrów w szablonach.


Następnie w szablonie możesz przypisać wartości do kontekstu w następujący sposób:

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

   {% define "Edit" as action %}

{% else %}

   {% define "Create" as action %}

{% endif %}


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

2
w moim przypadku po pętli zwraca to starą wartość :(
holms

7
W najnowszej wersji wydaje się, że możesz użyć simple_tag zamiast assignment_tag (i działało to dla mnie).
Katharine Osborne

Problem, który dostałem z tym rozwiązaniem, polega na tym, że wydaje się, że nie można przesłonić wartości.
Jakub Jabłoński

jeśli chcesz użyć tej techniki, aby ustawić listę zamiast tylko wartości, zaznacz to: stackoverflow.com/a/34407158/2193235
msb

jeśli ustawienie zmiennej w postaci liczby całkowitej i chcesz go (na przykład) zwiększyć, trzeba użyć add: {% define counter|add:1 as counter %}. Podobnie w przypadku innych operacji.
msb

35

Alternatywnym sposobem, który nie wymaga umieszczania wszystkiego w bloku „with”, jest utworzenie niestandardowego znacznika, który dodaje nową zmienną do kontekstu. Jak w:

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)

To pozwoli ci napisać coś takiego w swoim szablonie:

{% setvar "a string" as new_template_var %}

Zauważ, że większość z tego została zabrana stąd


Co powiesz na przypisanie zmiennych do innych zmiennych obecnych w kontekście? I z innej uwagi: zezwolenie szablonom na dowolne przypisywanie zmiennych kontekstowych bez sprawdzania, czy już istnieją, może mieć wpływ na bezpieczeństwo. Moim zdaniem bardziej rozsądnym podejściem byłoby sprawdzenie kontekstu dla zmiennej przed próbą jej przypisania:
soze

if context.get (self.var_name): podnoszenie SuspiciousOperation („Próba przypisania zmiennej z szablonu już obecnego w kontekście”)
soze

27

Istnieją sztuczki takie jak opisane przez Johna; jednak język szablonów Django według projektu nie obsługuje ustawiania zmiennej ( szablony można znaleźć w polu „Filozofia” w dokumentacji Django ).
Z tego powodu zalecanym sposobem zmiany dowolnej zmiennej jest dotknięcie kodu Pythona.


7
Dzięki za wskaźnik. Z perspektywy projektanta czasem łatwiej jest szybko ustawić zmienną, aby przetestować różne stany strony podczas jej projektowania. Nie sugeruje, aby tę praktykę stosować w działającym kodzie.
Alexis

2
znacznik „with” jest akceptowany w django1.0. Wygląda na to, że w końcu zmieniają swoją filozofię :).
Evgeny,

2
W rzeczywistości znacznik „with” służy tylko aliasom. Może to mieć ogromny wpływ na wydajność (a także na czytelność!), Ale tak naprawdę nie ustawia zmiennej w tradycyjnych terminach programowania.
rob

12

Najlepszym rozwiązaniem jest napisanie niestandardowego assignment_tag. To rozwiązanie jest bardziej czyste niż używanie withtagu, ponieważ zapewnia bardzo wyraźne oddzielenie logiki od stylu.

Zacznij od utworzenia pliku znacznika szablonu (np. appname/templatetags/hello_world.py):

from django import template

register = template.Library()

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

Teraz możesz używać get_addresseetagu szablonu w swoich szablonach:

{% load hello_world %}

{% get_addressee as addressee %}

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

3
Dla osób używających nowszych wersji Django, nazywa się teraz simple_tag! Zaoszczędź czas, aby dowiedzieć się, dlaczego „zarejestruj się” nie jest rozpoznawane w twoim kodzie ...
kaya

11

Być może defaultfiltr szablonu nie był opcją w 2009 roku ...

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

Muszę powiedzieć, że tego właśnie szukałem! Można go również stosować z : {% with state=form.state.value|default:other_context_variable %}zamiast other_context_variablemożemy również używać 'string_value'jako dobrze
Saurav Kumar

Ale to wydrukuje i muszę go zachować do późniejszego wykorzystania
Holms

4

To nie jest ogólnie dobry pomysł. Wykonaj całą logikę w pythonie i przekaż dane do szablonu w celu wyświetlenia. Szablon powinien być możliwie najprostszy, aby osoby pracujące nad projektem mogły skupić się na projekcie, a nie martwić się logiką.

Na przykład, jeśli potrzebujesz pewnych informacji pochodnych w szablonie, lepiej jest umieścić je w zmiennej w kodzie python, a następnie przekazać je do szablonu.


3

Użyj instrukcji with .

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

Nie mogę sugerować kodu z pierwszego akapitu tej odpowiedzi . Może język szablonów zastąpił stary format.


2

W swoim szablonie możesz to zrobić w następujący sposób:

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

W tagach szablonów możesz dodać taki tag:

@register.assignment_tag
def jump_link():
    listArr = []
    for i in range(5):
        listArr.append({"helo" : i,"how" : i})
    return listArr
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.