web-dev-qa-db-fra.com

Comment concaténer des chaînes dans Django modèles?

Je veux concaténer une chaîne dans une balise de modèle Django, comme:

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

Ici shop_name est ma variable et je veux concaténer cela avec reste de chemin.

Supposons que j'ai shop_name=example.com et que le résultat soit étendu shop/example.com/base.html.

178
Ahsan

Utiliser avec:

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

N'utilisez pas add pour les chaînes, vous devez définir une balise personnalisée comme celle-ci:

Créer un fichier: <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)

et ensuite l'utiliser comme dit @Steven

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

Raison pour éviter add

Selon le docs

Ce filtre va premier essayer de contraindre les deux valeurs à des entiers ... Les chaînes pouvant être forcées à des entiers seront additionnées, non concaténées ...

Si les deux variables sont des entiers, le résultat serait inattendu.

96
user

J'ai changé la hiérarchie des dossiers

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

et puis ci-dessous fonctionnerait.

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

Il est maintenant possible d’étendre la page base.html.

11
Ahsan

Jetez un coup d'œil au add filter .

Edit: Vous pouvez chaîner les filtres pour pouvoir utiliser "shop/"|add:shop_name|add:"/base.html". Mais cela ne fonctionnera pas, car il appartient à la balise template d'évaluer les filtres dans les arguments et ne l'étend pas.

Je suppose que vous ne pouvez pas faire cela dans les modèles.

3
Daniel Hepper

Reportez-vous à Concaténation de chaînes dans Django Modèles :

  1. Pour les versions antérieures de Django:

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

"Mary avait un petit agneau."

  1. Autre:

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

"Mary avait un petit agneau."

3
bing

De la docs:

Cette balise peut être utilisée de deux manières:

  • {% extends "base.html" %} (avec guillemets) utilise la valeur littérale "base.html" comme nom du modèle parent à étendre.
  • {% extends variable %} utilise la valeur de variable. Si la variable correspond à une chaîne, Django utilisera cette chaîne comme nom du modèle parent. Si la variable correspond à un objet Modèle, Django utilisera cet objet comme modèle parent.

Il semble donc que vous ne pouvez pas utiliser de filtre pour manipuler l'argument. Dans la vue d'appel, vous devez instancier le modèle d'ancêtre ou créer une variable chaîne avec le chemin correct et la transmettre avec le contexte.

2
Paulo Scardine

La réponse de @ error est fondamentalement juste, vous devriez utiliser une balise template pour cela. Cependant, je préfère une balise de modèle légèrement plus générique que je peux utiliser pour effectuer tout type d'opération similaire à celle-ci:

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

et ensuite vous pouvez l'utiliser comme ceci dans votre modèle:

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

Comme le commentaire le mentionne, cette balise de modèle est particulièrement utile pour les informations qui peuvent être répétées dans un modèle, mais qui nécessitent une logique et d'autres éléments permettant de supprimer vos modèles, ou dans les cas où vous souhaitez réutiliser des données transmises entre modèles par blocs:

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

puis:

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

Le crédit pour la balise captureas est dû ici: https://www.djangosnippets.org/snippets/545/

1
K3TH3R

J'ai trouvé que travailler avec la balise {% with %} était assez compliqué. Au lieu de cela, j'ai créé la balise de modèle suivante, qui devrait fonctionner sur les chaînes et les entiers.

from Django import template

register = template.Library()


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

Ensuite, chargez la balise de modèle dans votre modèle en haut en utilisant les éléments suivants:

{% load concat_string %}

Vous pouvez ensuite l'utiliser de la manière suivante:

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

Personnellement, j’ai trouvé que c’était beaucoup plus propre.

1
Bono

extends n'a aucune installation pour cela. Placez tout le chemin du modèle dans une variable de contexte et utilisez-le ou copiez la balise exist et modifiez-la de manière appropriée.

0

Vous ne pouvez pas manipuler de variable dans Django modèles. Vous avez deux options: écrire votre propre balise de gabarit ou le faire en vue,

0
damir