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?

Alexis
źródło

Odpowiedzi:

327

Możesz użyć withznacznika szablonu.

{% with name="World" %}     
<html>
<div>Hello {{name}}!</div>
</html>
{% endwith %}
Jan
źródło
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?
Mods Vs Rockers
źródło
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

Karim
źródło
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.

obrabować
źródło
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>
unikalny byt
źródło
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>
John Mee
źródło
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.

Sarang
źródło
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.

ramwin
źródło
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
Ashish Gupta
źródło