Как установить значение переменной внутри кода шаблона?

217

Скажи у меня есть шаблон

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

При тестировании было бы полезно определить значение переменной, не касаясь кода Python, который вызывает этот шаблон. Поэтому я ищу что-то вроде этого

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

Существует ли что-то подобное в Джанго?

Alexis
источник

Ответы:

328

Вы можете использовать withтег шаблона.

{% with name="World" %}     
<html>
<div>Hello {{name}}!</div>
</html>
{% endwith %}
Джон
источник
35
но вы можете изменить значение переменной в с?
Дэвид 天宇 Вонг
2
Кажется, вы не можете объявить контейнер (я пробовал список и кортеж) в предложении with
Владислав Иванишин
Если вам нужно объявить список, используйте make_list. docs.djangoproject.com/en/1.9/ref/templates/builtins/#make-list
MrValdez
3
Джинджа говорит, что {% set myvar = value%} почему это не работает в django?
Холмс
3
@holms Потому что Джанго не использует Джинджу
elimisteve
50

Создайте тег шаблона:

Приложение должно содержать templatetagsкаталог, на том же уровне , как models.py, views.pyи т.д. Если это не существует, создайте его - не забудьте __init__.pyфайл , чтобы обеспечить каталог рассматривается как пакет Python.

Создайте файл с именем define_action.pyвнутри каталога templatetags со следующим кодом:

from django import template
register = template.Library()

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

Примечание. Сервер разработки не будет автоматически перезагружен. После добавления templatetagsмодуля вам нужно будет перезагрузить сервер, прежде чем вы сможете использовать теги или фильтры в шаблонах.


Затем в вашем шаблоне вы можете присвоить значения контексту следующим образом:

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

   {% define "Edit" as action %}

{% else %}

   {% define "Create" as action %}

{% endif %}


Would you like to {{action}} this item?
Моды против Рокеров
источник
2
в моем случае после цикла это возвращает старое значение :(
holms
7
В последней версии кажется, что вы можете использовать simple_tag вместо assignment_tag (и у меня это сработало).
Кэтрин Осборн
Проблема, которую я получил с этим решением, заключается в том, что кажется, что вы не можете переопределить значения.
Якуб Яблонский
если вы хотите использовать эту технику для установки списка вместо просто значения, проверьте это: stackoverflow.com/a/34407158/2193235
msb
если вы устанавливаете переменную как целое , и вы хотите увеличить его (например), вы должны использовать add: {% define counter|add:1 as counter %}. Аналогично для других операций.
MSB
35

Альтернативный способ, который не требует, чтобы вы помещали все в блок «with», - это создание пользовательского тега, который добавляет новую переменную в контекст. Как в:

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)

Это позволит вам написать что-то вроде этого в вашем шаблоне:

{% setvar "a string" as new_template_var %}

Обратите внимание, что большая часть этого была взята отсюда

Karim
источник
Как насчет присвоения переменных другим переменным, присутствующим в контексте? И еще одно замечание: разрешение шаблонам произвольно назначать переменные контекста без проверки того, существуют ли они уже, может иметь последствия для безопасности. На мой взгляд, более разумным подходом было бы проверить контекст для переменной, прежде чем пытаться присвоить ее:
soze
if context.get (self.var_name): повысить SuspiciousOperation («Попытка назначить переменную из шаблона, уже присутствующего в контексте»)
soze
27

Есть трюки, подобные описанному Джоном; однако язык шаблонов Django по своему дизайну не поддерживает установку переменной (см. блок «Философия» в документации Django для шаблонов ).
Из-за этого рекомендуемый способ изменить любую переменную - прикоснуться к коду Python.

грабить
источник
7
Спасибо за указатель. С точки зрения дизайнера, иногда проще быстро установить переменную для проверки различных состояний страницы при ее разработке. Не предлагать эту практику для использования в работающем коде.
Алексис
2
тег "с" принят в django1.0. Похоже, они наконец-то поправляют свою философию :).
Евгений
2
На самом деле, тег «с» предназначен только для псевдонимов. Это может оказать огромное влияние на производительность (и на удобочитаемость!), Но на самом деле это не установка переменной в традиционных терминах программирования.
ограбить
12

Лучшее решение для этого - написать кастом assignment_tag. Это решение более чистое, чем использование withтега, поскольку оно обеспечивает очень четкое разделение между логикой и стилем.

Начните с создания файла шаблона тега (например. appname/templatetags/hello_world.py):

from django import template

register = template.Library()

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

Теперь вы можете использовать get_addresseeтег шаблона в ваших шаблонах:

{% load hello_world %}

{% get_addressee as addressee %}

<html>
    <body>
        <h1>hello {{addressee}}</h1>
    </body>
</html>
уникальный объект
источник
3
Для людей, использующих более новые версии Django, его теперь называют simple_tag! Сэкономьте время, чтобы выяснить, почему "регистрация .." не распознается в вашем коде ...
kaya
11

Возможно, defaultшаблон фильтра не был вариант еще в 2009 году ...

<html>
<div>Hello {{name|default:"World"}}!</div>
</html>
Джон Ми
источник
Сразу скажу, что это то, что я искал! Он может быть также использован с с : {% with state=form.state.value|default:other_context_variable %}вместо того , other_context_variableмы также можем использовать любой , 'string_value'а также
Saurav Кумар
Но он напечатает его, и мне нужно сохранить его для дальнейшего использования
holms
4

Это не очень хорошая идея в целом. Выполните всю логику в python и передайте данные в шаблон для отображения. Шаблон должен быть как можно более простым, чтобы те, кто работает над дизайном, могли сосредоточиться на дизайне, а не беспокоиться о логике.

Например, если вам нужна некоторая производная информация в шаблоне, лучше поместить ее в переменную в коде Python, а затем передать ее в шаблон.

Sarang
источник
3

Используйте оператор with .

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

Я не могу подразумевать код в первом абзаце в этом ответе . Возможно, язык шаблонов устарел в старом формате.

ramwin
источник
2

В вашем шаблоне вы можете сделать так:

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

В ваш шаблон-теги вы можете добавить такой тег:

@register.assignment_tag
def jump_link():
    listArr = []
    for i in range(5):
        listArr.append({"helo" : i,"how" : i})
    return listArr
Ашиш Гупта
источник