Jak połączyć łańcuchy w szablonach django?

191

Chcę połączyć łańcuch w znaczniku szablonu Django, na przykład:

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

Oto shop_namemoja zmienna i chcę połączyć to z resztą ścieżki.

Załóżmy, że mam shop_name=example.comi chcę, aby wynik przedłużył się shop/example.com/base.html.

Ahsan
źródło

Odpowiedzi:

380

Używać z:

{% with "shop/"|add:shop_name|add:"/base.html" as template %}
{% include template %}
{% endwith %}
Steven
źródło
2
Byłem całkowicie zdezorientowany tą odpowiedzią, ponieważ używa tagu włączenia zamiast tagu rozszerzenia, ale najwyraźniej po prostu działa. Chociaż poleciłbym własną odpowiedź Ahsana, ponieważ również działa i jest (moim zdaniem) semantycznie bardziej poprawna i powoduje mniej zamieszania.
gitaarik
15
Może to działać, ale nie powinno być traktowane jako ogólna odpowiedź na łączenie ciągów w szablonach django. Zobacz stackoverflow.com/a/23783666/781695
użytkownik
Jak powiedziano w dokumentacji Django: „Ciągi, które można przekonwertować na liczby całkowite, będą sumowane, a nie konkatenowane”. Na przykład, jeśli chcesz połączyć klucze podstawowe obiektu modelu (może to być przydatne do utworzenia unikalnego klucza pamięci podręcznej), nie praca.
zen11625
Myślę, że to wcale nie ucieka shop_name, więc jest niebezpieczne.
Flimm
Pamiętaj, jak już wspomniano, działa to tylko z łańcuchami! Jeśli tłumaczysz shop_nameprzed przekazaniem go do kontekstu w widoku, get_context_dataupewnij się, że jest tłumaczony przy użyciu ugettextzamiast ugettext_lazy.
Kim
111

Nie używaj addciągów znaków, powinieneś zdefiniować niestandardowy tag, taki jak ten:

Utwórz plik: <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)

a następnie użyj go, jak mówi @Steven

{% load <appname>_extras %}

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

Powód unikania add:

Według dokumentów

Ten filtr najpierw spróbuje wymusić obie wartości na liczbach całkowitych ... Ciągi, które można wymusić na liczbach całkowitych, zostaną zsumowane, a nie połączone ...

Gdyby obie zmienne były liczbami całkowitymi, wynik byłby nieoczekiwany.

użytkownik
źródło
Czy nie powinno to być @ register.filter (name = 'addstr')?
seddonym
6
Powinno to zostać oznaczone jako najlepsza odpowiedź, ponieważ działa poprawnie z wartościami, które Python może wymusić jako liczby całkowite.
zen11625
2
Nie wiem, dlaczego nie jesteś tym, który jest najbardziej „podwyższony”, ponieważ tak jest twoja odpowiedź jest prawidłowa, sama „ add” po prostu nie używa str()na pierwszym miejscu i nie działała w ogóle dla mnie, podczas gdy twoje rozwiązanie działa bezbłędnie
Olivier Pons
1
Twoja odpowiedź mnie uratowała!
Ljubisa Livac
6
Pamiętaj, aby załadować własny filtr u góry pliku szablonu:{% load <appname>_extras %}
Susanne Peng
13

Zmieniłem hierarchię folderów

/shop/shop_name/base.html Do /shop_name/shop/base.html

a następnie poniżej będzie działać.

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

Teraz jest w stanie rozszerzyć stronę base.html.

Ahsan
źródło
7

Zobacz Łączenie ciągów w szablonach Django :

  1. W przypadku wcześniejszych wersji Django:

    {{ "Mary had a little"|stringformat:"s lamb." }}

"Mary miała małe jagnię."

  1. Jeszcze:

    {{ "Mary had a little"|add:" lamb." }}

"Mary miała małe jagnię."

bing
źródło
3

Spójrz na addfiltr .

Edycja: możesz łączyć filtry, więc możesz to zrobić "shop/"|add:shop_name|add:"/base.html". Ale to nie zadziała, ponieważ ocena szablonu w argumentach zależy od tagu szablonu, a rozszerzenie nie.

Myślę, że nie możesz tego zrobić w szablonach.

Daniel Hepper
źródło
to nie zadziała. chcę dodać moją zmienną na środku ścieżki.
Ahsan,
dodaj filtr tylko zsumowany nie konkatenuje zgodnie z dokumentami django
Ahsan
Dokumenty mówią „ciągi, które można wymusić na liczby całkowite, zostaną zsumowane”. Inne łańcuchy są łączone. Ale to tak naprawdę nie ma znaczenia, ponieważ nie można użyć filtra :(
Daniel Hepper
2

Z dokumentów:

Tego znacznika można użyć na dwa sposoby:

  • {% extends "base.html" %} (z cudzysłowami) używa wartości literału „base.html” jako nazwy szablonu nadrzędnego, który ma zostać rozszerzony.
  • {% extends variable %}używa wartości zmiennej. Jeśli zmienna ma wartość ciągu, Django użyje tego ciągu jako nazwy szablonu nadrzędnego. Jeśli zmienna zostanie przekształcona w obiekt szablonu, Django użyje tego obiektu jako szablonu nadrzędnego.

Wygląda na to, że nie możesz użyć filtra do manipulowania argumentem. W widoku wywołującym musisz utworzyć instancję szablonu przodka lub utworzyć zmienną łańcuchową z poprawną ścieżką i przekazać ją z kontekstem.

Paulo Scardine
źródło
1

Odpowiedź @ error jest zasadniczo poprawna, powinieneś do tego użyć tagu szablonu. Jednak wolę nieco bardziej ogólny tag szablonu, którego mogę używać do wykonywania wszelkiego rodzaju operacji podobnych do tego:

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 ''

a następnie możesz użyć go w ten sposób w swoim szablonie:

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

Jak wspomniano w komentarzu, ten znacznik szablonu jest szczególnie użyteczny w przypadku informacji, które są powtarzalne w szablonie, ale wymagają logiki i innych rzeczy, które rozgromią twoje szablony lub w przypadkach, w których chcesz ponownie wykorzystać dane przekazywane między szablonami przez bloki:

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

i wtedy:

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

Kredyt na tag captureas należy się tutaj: https://www.djangosnippets.org/snippets/545/

K3TH3R
źródło
1

Praca z {% with %}tagiem była dość kłopotliwa. Zamiast tego utworzyłem następujący znacznik szablonu, który powinien działać na ciągach i liczbach całkowitych.

from django import template

register = template.Library()


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

Następnie załaduj tag szablonu do szablonu u góry, korzystając z następujących czynności:

{% load concat_string %}

Następnie możesz użyć go w następujący sposób:

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

Osobiście uważam, że jest o wiele czystszy w pracy.

Bono
źródło
0

W szablonach django nie można manipulować zmiennymi. Masz dwie opcje: albo napisz własny tag szablonu, albo zrób to w widoku,

damir
źródło
moim wymaganiem jest robienie tego tylko w szablonach, więc opcja widoków nie jest pomocna. Próbowałem także za pomocą niestandardowego tagu szablonu, ale {% load concat%} powinien znajdować się po tagu {% ext ....%}. więc jak mogę to teraz zrobić?
Ahsan,
Napisz tag Extended_extends, który akceptuje format ciągu i argumenty.
Paulo Scardine,
czy możesz podać przykład pisania niestandardowych tagów dla domyślnych?
Ahsan,
0

extendsnie ma na to możliwości. Umieść całą ścieżkę szablonu w zmiennej kontekstowej i użyj jej, lub skopiuj istniejący znacznik szablonu i odpowiednio go zmodyfikuj.

Ignacio Vazquez-Abrams
źródło
dzięki za odpowiedź! dla zmiennej kontekstowej muszę ustawić w view.py, którego nie mogę ze względu na mój projekt. i proszę podać przykład drugiego.
Ahsan,
0

I wiele konkatenacji:

from django import template
register = template.Library()


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

I w szablonie:

{% concat_all 'x' 'y' another_var as string_result %}
concatenated string: {{ string_result }}
Gassan
źródło