Как объединить строки в шаблонах Django?

191

Я хочу объединить строку в теге шаблона Django, например:

{% extend shop/shop_name/base.html %}

Вот shop_nameмоя переменная, и я хочу объединить это с остальной частью пути.

Предположим, у меня есть shop_name=example.comи я хочу, чтобы результат был расширен shop/example.com/base.html.

Ahsan
источник

Ответы:

380

Использовать с:

{% with "shop/"|add:shop_name|add:"/base.html" as template %}
{% include template %}
{% endwith %}
Стивен
источник
2
Я был полностью смущен этим ответом, так как он использует тег include вместо тега extension, но, очевидно, он просто работает. Хотя я бы порекомендовал собственный ответ Асана, так как он также работает и (на мой взгляд) семантически более корректен и вызывает меньше путаницы.
Гитаарик
15
Это может работать, но не должно рассматриваться как общий ответ для объединения строк в шаблонах django. См. Stackoverflow.com/a/23783666/781695
пользователь
Как говорится в документации Django: «Строки, которые можно привести к целым числам, будут суммироваться, а не объединяться». Так, например, если вы хотите объединить первичные ключи объекта модели (может быть полезно для создания уникального ключа кэша), это не работай.
zen11625
Я думаю, что это не избежать shop_name, так что это опасно.
Flimm
Имейте в виду, как уже упоминалось, это работает только со строками! Если вы переводите shop_nameперед передачей его контексту в представлении, get_context_dataубедитесь, что он переведен с использованием ugettextвместо ugettext_lazy.
Ким
111

Не используйте addдля строк, вы должны определить пользовательский тег следующим образом:

Создать файл: <appname>\templatetags\<appname>_extras.py

from django import template

register = template.Library()

@register.filter
def addstr(arg1, arg2):
    """concatenate arg1 & arg2"""
    return str(arg1) + str(arg2)

а затем используйте его, как говорит @Steven

{% load <appname>_extras %}

{% with "shop/"|addstr:shop_name|addstr:"/base.html" as template %}
    {% include template %}
{% endwith %}

Причина, по которой следует избегать add:

Согласно документам

Этот фильтр сначала попытается привести оба значения к целым числам ... Строки, которые можно привести к целым числам, будут суммироваться, а не объединяться ...

Если обе переменные являются целыми числами, результат будет неожиданным.

пользователь
источник
Разве это не должно быть @ register.filter (name = 'addstr')?
seddonym
6
Это должно быть помечено как лучший ответ, потому что правильно работает со значениями, которые могут быть приведены в Python как целые числа.
zen11625 25.09.15
2
Я не знаю, почему вы не тот, у кого больше всего «вверх», потому что это ваш правильный ответ, что add«один» просто не использует str()в первую очередь и не работает для меня вообще , тогда как ваше решение работает без нареканий
Оливье Понс
1
Ваш ответ спас меня!
Любиса Ливак
6
Не забудьте загрузить свой пользовательский фильтр вверху файла шаблона:{% load <appname>_extras %}
Сюзанна Пенг
13

Я изменил иерархию папок

/shop/shop_name/base.html To /shop_name/shop/base.html

и тогда ниже будет работать.

{% extends shop_name|add:"/shop/base.html"%} 

Теперь можно расширять страницу base.html.

Ahsan
источник
3

Посмотрите на addфильтр .

Изменить: вы можете цепочки фильтров, чтобы вы могли сделать "shop/"|add:shop_name|add:"/base.html". Но это не сработает, потому что это зависит от тега шаблона для оценки фильтров в аргументах, а расширение не работает.

Я думаю, вы не можете сделать это в шаблонах.

Дэниел Хеппер
источник
это не сработает. Я хочу добавить свою переменную в середине пути.
Ахсан
добавить фильтр только суммированный, не объединенный в соответствии с документами Django
Ahsan
В документах сказано, что «строки, которые можно привести к целым числам, будут суммированы». Другие строки объединяются. Но это все равно не имеет значения, потому что вы не можете использовать фильтр :(
Даниэль Хеппер
2

Из документов:

Этот тег можно использовать двумя способами:

  • {% extends "base.html" %} (с кавычками) использует литеральное значение "base.html" в качестве имени родительского шаблона для расширения.
  • {% extends variable %}использует значение переменной. Если переменная оценивается как строка, Django будет использовать эту строку в качестве имени родительского шаблона. Если переменная оценивается как объект Template, Django будет использовать этот объект в качестве родительского шаблона.

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

Пауло Скардин
источник
1

Ответ @ error в корне верен, для этого вы должны использовать тег шаблона. Однако я предпочитаю чуть более универсальный тег шаблона, который я могу использовать для выполнения любых операций, подобных этому:

from django import template
register = template.Library()


@register.tag(name='captureas')
def do_captureas(parser, token):
    """
    Capture content for re-use throughout a template.
    particularly handy for use within social meta fields 
    that are virtually identical. 
    """
    try:
        tag_name, args = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError("'captureas' node requires a variable name.")
    nodelist = parser.parse(('endcaptureas',))
    parser.delete_first_token()
    return CaptureasNode(nodelist, args)


class CaptureasNode(template.Node):
    def __init__(self, nodelist, varname):
        self.nodelist = nodelist
        self.varname = varname

    def render(self, context):
        output = self.nodelist.render(context)
        context[self.varname] = output
        return ''

и тогда вы можете использовать это в своем шаблоне:

{% captureas template %}shop/{{ shop_name }}/base.html{% endcaptureas %}
{% include template %}

Как упоминается в комментарии, этот тег шаблона особенно полезен для информации, которая повторяется по всему шаблону, но требует логики и других вещей, которые будут мешать вашим шаблонам, или в случаях, когда вы хотите повторно использовать данные, передаваемые между шаблонами через блоки:

{% captureas meta_title %}{% spaceless %}{% block meta_title %}
    {% if self.title %}{{ self.title }}{% endif %}
    {% endblock %}{% endspaceless %} - DEFAULT WEBSITE NAME
{% endcaptureas %}

а потом:

<title>{{ meta_title }}</title>
<meta property="og:title" content="{{ meta_title }}" />
<meta itemprop="name" content="{{ meta_title }}">
<meta name="twitter:title" content="{{ meta_title }}">

Кредит на тег captureas можно получить здесь: https://www.djangosnippets.org/snippets/545/

K3TH3R
источник
1

Работа с {% with %}тегом показалась мне довольно сложной. Вместо этого я создал следующий тег шаблона, который должен работать со строками и целыми числами.

from django import template

register = template.Library()


@register.filter
def concat_string(value_1, value_2):
    return str(value_1) + str(value_2)

Затем загрузите тег шаблона в свой шаблон вверху, используя следующее:

{% load concat_string %}

Затем вы можете использовать его следующим образом:

<a href="{{ SOME_DETAIL_URL|concat_string:object.pk }}" target="_blank">123</a>

Лично я нашел, что с этим работать намного чище.

Боно
источник
0

Вы не можете делать переменные в шаблонах Django. У вас есть два варианта: либо написать свой собственный тег шаблона, либо сделать это на виду,

Дамир
источник
мое требование состоит в том, чтобы сделать это только в шаблонах, поэтому опция просмотра не помогает. Я также пытался с помощью пользовательского тега шаблона, но {% load concat%} следует после тега {% extension ....%}. так как я могу сделать это сейчас?
Ахсан
Напишите тег extended_extends, который принимает формат строки и аргументы.
Пауло Скардин
Можете ли вы дать мне пример того, как написать пользовательские теги для стандартных?
Асан
0

extendsне имеет возможности для этого. Либо поместите весь путь шаблона в переменную контекста и используйте его, либо скопируйте существующий тег шаблона и измените его соответствующим образом.

Игнасио Васкес-Абрамс
источник
Спасибо за ответ! для переменной контекста я должен установить в view.py, который я не могу из-за требований моего проекта. и, пожалуйста, приведите пример второго.
Ахсан
0

И множественная конкатенация:

from django import template
register = template.Library()


@register.simple_tag
def concat_all(*args):
    """concatenate all args"""
    return ''.join(map(str, args))

И в шаблоне:

{% concat_all 'x' 'y' another_var as string_result %}
concatenated string: {{ string_result }}
Гассан
источник