Wie verkette ich Strings in Django-Vorlagen?

189

Ich möchte eine Zeichenfolge in einem Django-Vorlagen-Tag verketten, z.

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

Hier shop_nameist meine Variable und ich möchte diese mit dem Rest des Pfades verketten.

Angenommen, ich habe shop_name=example.comund ich möchte, dass sich das Ergebnis erweitert shop/example.com/base.html.

Ahsan
quelle

Antworten:

379

Benutzen mit:

{% with "shop/"|add:shop_name|add:"/base.html" as template %}
{% include template %}
{% endwith %}
Steven
quelle
2
Ich war total verwirrt von dieser Antwort, da sie das Include-Tag anstelle des Extend-Tags verwendet, aber anscheinend funktioniert es einfach. Obwohl ich Ahsans eigene Antwort empfehlen würde, da sie auch funktioniert und (meiner Meinung nach) semantisch korrekter ist und weniger Verwirrung stiftet.
Gitaarik
15
Dies mag funktionieren, sollte aber nicht als allgemeine Antwort auf die Verkettung von Zeichenfolgen in Django-Vorlagen angesehen werden. Siehe stackoverflow.com/a/23783666/781695
Benutzer
In der Django-Dokumentation heißt es: "Zeichenfolgen, die zu Ganzzahlen gezwungen werden können, werden summiert und nicht verkettet." Wenn Sie beispielsweise die Primärschlüssel des Modellobjekts verketten möchten (dies kann nützlich sein, um einen eindeutigen Cache-Schlüssel zu erstellen), ist dies nicht der Fall Arbeit.
Zen11625
Ich denke, das entgeht überhaupt nicht shop_name, also ist es gefährlich.
Flimm
Beachten Sie, wie bereits erwähnt, dass dies nur mit Zeichenfolgen funktioniert! Wenn Sie übersetzen, shop_namebevor Sie es an den Kontext in einer Ansicht übergeben, get_context_datastellen Sie sicher, dass es mit ugettextanstelle von übersetzt wird ugettext_lazy.
Kim
111

Nicht addfür Zeichenfolgen verwenden, Sie sollten ein benutzerdefiniertes Tag wie folgt definieren:

Erstellen Sie eine Datei: <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)

und dann benutze es wie @Steven sagt

{% load <appname>_extras %}

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

Grund zur Vermeidung add:

Laut den Dokumenten

Dieser Filter versucht zuerst , beide Werte zu ganzen Zahlen zu zwingen ... Zeichenfolgen, die zu ganzen Zahlen gezwungen werden können, werden summiert und nicht verkettet ...

Wenn beide Variablen Ganzzahlen sind, ist das Ergebnis unerwartet.

Benutzer
quelle
Sollte das nicht @ register.filter sein (name = 'addstr')?
Seddonym
6
Dies sollte als beste Antwort markiert werden, da mit Werten, die von Python als Ganzzahlen erzwungen werden können, korrekt gearbeitet wird.
Zen11625
2
Ich weiß nicht, warum Sie nicht derjenige sind, der am meisten "up" ist, weil es Ihre Antwort ist, die richtig ist. Das " add" allein wird einfach nicht str()an erster Stelle verwendet und hat bei mir überhaupt nicht funktioniert , während Ihre Lösung einwandfrei funktioniert
Olivier Pons
1
Deine Antwort hat mich gerettet!
Ljubisa Livac
6
Denken Sie daran, Ihren benutzerdefinierten Filter oben in Ihre Vorlagendatei zu laden:{% load <appname>_extras %}
Susanne Peng
13

Ich habe die Ordnerhierarchie geändert

/shop/shop_name/base.html An /shop_name/shop/base.html

und dann unten würde funktionieren.

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

Jetzt kann die base.html-Seite erweitert werden.

Ahsan
quelle
7

Siehe Verketten von Zeichenfolgen in Django-Vorlagen :

  1. Für frühere Versionen von Django:

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

"Mary hatte ein kleines Lamm."

  1. Sonst:

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

"Mary hatte ein kleines Lamm."

bing
quelle
3

Schauen Sie sich den addFilter an .

Bearbeiten: Sie können Filter verketten, damit Sie dies tun können "shop/"|add:shop_name|add:"/base.html". Dies funktioniert jedoch nicht, da es an der Vorlage liegt, Filter in Argumenten auszuwerten, und erweitert dies nicht.

Ich denke, Sie können dies nicht in Vorlagen tun.

Daniel Hepper
quelle
das wird nicht funktionieren. Ich möchte meine Variable in der Mitte des Pfades hinzufügen.
Ahsan
Filter hinzufügen nur summiert nicht verkettet gemäß Django Docs
Ahsan
Die Dokumente sagen, dass "Zeichenfolgen, die zu ganzen Zahlen gezwungen werden können, summiert werden". Andere Zeichenfolgen werden verkettet. Aber das ist sowieso nicht wirklich wichtig, weil Sie den Filter nicht verwenden können :(
Daniel Hepper
2

Aus den Dokumenten:

Dieses Tag kann auf zwei Arten verwendet werden:

  • {% extends "base.html" %} (mit Anführungszeichen) verwendet den Literalwert "base.html" als Namen der zu erweiternden übergeordneten Vorlage.
  • {% extends variable %}verwendet den Wert der Variablen. Wenn die Variable eine Zeichenfolge ergibt, verwendet Django diese Zeichenfolge als Namen der übergeordneten Vorlage. Wenn die Variable zu einem Vorlagenobjekt ausgewertet wird, verwendet Django dieses Objekt als übergeordnete Vorlage.

Es scheint also, dass Sie keinen Filter verwenden können, um das Argument zu manipulieren. In der aufrufenden Ansicht müssen Sie entweder die Ahnenvorlage instanziieren oder eine Zeichenfolgenvariable mit dem richtigen Pfad erstellen und mit dem Kontext übergeben.

Paulo Scardine
quelle
1

Die Antwort von @ error ist grundsätzlich richtig. Sie sollten hierfür ein Template-Tag verwenden. Ich bevorzuge jedoch ein etwas allgemeineres Vorlagen-Tag, mit dem ich ähnliche Vorgänge ausführen kann:

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

und dann können Sie es so in Ihrer Vorlage verwenden:

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

Wie im Kommentar erwähnt, ist dieses Vorlagen-Tag besonders nützlich für Informationen, die in einer Vorlage wiederholbar sind, jedoch Logik und andere Dinge erfordern, die Ihre Vorlagen beschädigen, oder in Fällen, in denen Sie Daten, die zwischen Vorlagen über Blöcke übertragen werden, wiederverwenden möchten:

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

und dann:

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

Die Gutschrift für das Captureas-Tag ist hier fällig: https://www.djangosnippets.org/snippets/545/

K3TH3R
quelle
1

Ich fand die Arbeit mit dem {% with %}Tag ziemlich mühsam. Stattdessen habe ich das folgende Vorlagen-Tag erstellt, das für Zeichenfolgen und Ganzzahlen funktionieren soll.

from django import template

register = template.Library()


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

Laden Sie dann das Vorlagen-Tag oben in Ihre Vorlage wie folgt:

{% load concat_string %}

Sie können es dann folgendermaßen verwenden:

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

Ich persönlich fand es viel sauberer, damit zu arbeiten.

Bono
quelle
0

In Django-Vorlagen können Sie keine Variablen bearbeiten. Sie haben zwei Möglichkeiten: Schreiben Sie entweder Ihr eigenes Vorlagen-Tag oder tun Sie dies in der Ansicht.

Damir
quelle
Meine Anforderung besteht darin, dies nur in Vorlagen zu tun, sodass die Ansichtsoption nicht hilfreich ist. Ich habe es auch über ein benutzerdefiniertes Vorlagen-Tag versucht, aber {% load concat%} sollte nach dem Tag {% verlängern ....%}. Wie kann ich das jetzt machen?
Ahsan
Schreiben Sie ein erweitertes_extends-Tag, das ein Zeichenfolgenformat und Argumente akzeptiert.
Paulo Scardine
Kannst du mir bitte ein Beispiel geben, wie man benutzerdefinierte Tags für Standard-Tags schreibt?
Ahsan
0

extendshat keine Möglichkeit dafür. Fügen Sie entweder den gesamten Vorlagenpfad in eine Kontextvariable ein und verwenden Sie diese, oder kopieren Sie das vorhandene Vorlagen-Tag und ändern Sie es entsprechend.

Ignacio Vazquez-Abrams
quelle
Danke für die Antwort! Für die Kontextvariable muss ich in view.py festlegen, was ich aufgrund meiner Projektanforderungen nicht kann. und bitte geben Sie ein Beispiel für das zweite.
Ahsan
0

Und mehrfache Verkettung:

from django import template
register = template.Library()


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

Und in Vorlage:

{% concat_all 'x' 'y' another_var as string_result %}
concatenated string: {{ string_result }}
Gassan
quelle