¿Cómo concatenar cadenas en plantillas django?

189

Quiero concatenar una cadena en una etiqueta de plantilla de Django, como:

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

Aquí shop_nameestá mi variable y quiero concatenar esto con el resto del camino.

Supongamos que tengo shop_name=example.comy quiero ampliar el resultado shop/example.com/base.html.

Ahsan
fuente

Respuestas:

379

Usar con:

{% with "shop/"|add:shop_name|add:"/base.html" as template %}
{% include template %}
{% endwith %}
Steven
fuente
2
Esta respuesta me confundió totalmente, ya que usa la etiqueta de inclusión en lugar de la etiqueta de extensión, pero aparentemente simplemente funciona. Aunque recomendaría la propia respuesta de Ahsan, ya que también funciona y es (en mi opinión) semánticamente más correcta y genera menos confusión.
gitaarik
15
Esto puede funcionar, pero no debe considerarse como una respuesta general para concatenar cadenas en plantillas de django. Ver stackoverflow.com/a/23783666/781695
usuario
Como dice el refrán en la documentación de Django, "Las cadenas que se pueden convertir a enteros se sumarán, no se concatenarán". Por ejemplo, si desea concatenar las claves primarias del objeto modelo (puede ser útil para crear una clave de caché única), no trabajo.
zen11625
Creo que esto no se escapa shop_nameen absoluto, por lo que es peligroso.
Flimm
Tenga en cuenta, como ya se mencionó, ¡esto funciona solo con cadenas! Si traduce shop_nameantes de pasarlo al contexto en una vista, get_context_dataasegúrese de que se traduzca usando en ugettextlugar de ugettext_lazy.
Kim
111

No use addpara cadenas, debe definir una etiqueta personalizada como esta:

Crea un archivo: <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)

y luego úsalo como dice @Steven

{% load <appname>_extras %}

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

Motivo para evitar add:

De acuerdo con los documentos

Este filtro primero intentará forzar ambos valores a enteros ... Las cadenas que se pueden forzar a enteros se sumarán, no se concatenarán ...

Si ambas variables son enteras, el resultado sería inesperado.

usuario
fuente
¿No debería ser eso @ register.filter (name = 'addtr')?
seddonym
66
Esto debe marcarse como la mejor respuesta porque funciona correctamente con valores que Python puede forzar como enteros.
zen11625
2
No sé por qué usted no es el que tiene más "arriba" porque es su respuesta que es correcto, el " add" solo simplemente no utilizar str()en primer lugar y no funcionaba en absoluto para mí mientras que su solución funciona a la perfección
Olivier Pons el
1
¡Tu respuesta me ha salvado!
Ljubisa Livac
66
Recuerde cargar su filtro personalizado en la parte superior de su archivo de plantilla:{% load <appname>_extras %}
Susanne Peng
13

He cambiado la jerarquía de carpetas.

/shop/shop_name/base.html A /shop_name/shop/base.html

y luego a continuación funcionaría.

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

Ahora es capaz de extender la página base.html.

Ahsan
fuente
3

Echa un vistazo al addfiltro .

Editar: puede encadenar filtros, para que pueda hacerlo "shop/"|add:shop_name|add:"/base.html". Pero eso no funcionará porque depende de la etiqueta de la plantilla evaluar los filtros en los argumentos, y las extensiones no lo hacen.

Supongo que no puedes hacer esto dentro de las plantillas.

Daniel Hepper
fuente
Esto no va a funcionar. Quiero agregar mi variable en medio de la ruta.
Ahsan
agregar filtro solo sumado no concatenar de acuerdo con los documentos de django
Ahsan
Los documentos dicen "se sumarán las cadenas que se pueden coaccionar a enteros". Otras cadenas están concatenadas. Pero eso no importa de todos modos porque no puedes usar el filtro :(
Daniel Hepper
2

De los documentos:

Esta etiqueta se puede usar de dos maneras:

  • {% extends "base.html" %} (con comillas) utiliza el valor literal "base.html" como el nombre de la plantilla principal para ampliar.
  • {% extends variable %}usa el valor de variable. Si la variable se evalúa como una cadena, Django usará esa cadena como el nombre de la plantilla principal. Si la variable se evalúa como un objeto Plantilla, Django usará ese objeto como plantilla principal.

Parece que no puedes usar un filtro para manipular el argumento. En la vista de llamada, debe crear una instancia de la plantilla de antepasado o crear una variable de cadena con la ruta correcta y pasarla con el contexto.

Paulo Scardine
fuente
1

La respuesta de @ error es fundamentalmente correcta, debe usar una etiqueta de plantilla para esto. Sin embargo, prefiero una etiqueta de plantilla un poco más genérica que pueda usar para realizar cualquier tipo de operaciones similares a esta:

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

y luego puedes usarlo así en tu plantilla:

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

Como se menciona en el comentario, esta etiqueta de plantilla es particularmente útil para la información que se puede repetir a través de una plantilla pero requiere lógica y otras cosas que agruparán sus plantillas, o en los casos en que desee reutilizar los datos pasados ​​entre plantillas a través de bloques:

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

y entonces:

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

El crédito para la etiqueta captureas se debe aquí: https://www.djangosnippets.org/snippets/545/

K3TH3R
fuente
1

Encontré que trabajar con la {% with %}etiqueta es bastante complicado. En su lugar, creé la siguiente etiqueta de plantilla, que debería funcionar en cadenas y enteros.

from django import template

register = template.Library()


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

Luego cargue la etiqueta de plantilla en su plantilla en la parte superior usando lo siguiente:

{% load concat_string %}

Luego puede usarlo de la siguiente manera:

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

Personalmente, encontré que esto es mucho más limpio para trabajar.

Bono
fuente
0

No puedes hacer manipulación de variables en las plantillas de django. Tiene dos opciones: escribir su propia etiqueta de plantilla o hacer esto a la vista,

damir
fuente
mi requisito es hacerlo solo en plantillas, por lo que la opción de vistas no es útil. También probé a través de una etiqueta de plantilla personalizada, pero {% load concat%} debería después de la etiqueta {% extender ....%}. Entonces, ¿cómo puedo hacerlo ahora?
Ahsan
Escriba una etiqueta extendida_extensiones que acepte un formato de cadena y argumentos.
Paulo Scardine
¿Me puede dar un ejemplo de cómo escribir etiquetas personalizadas para las predeterminadas?
Ahsan
0

extendsno tiene facilidades para esto. Coloque la ruta completa de la plantilla en una variable de contexto y úsela, o copie la etiqueta de plantilla existente y modifíquela adecuadamente.

Ignacio Vazquez-Abrams
fuente
Gracias por la respuesta! para la variable de contexto tengo que establecer en view.py que no puedo debido a los requisitos de mi proyecto. y por favor dar ejemplo de la segunda.
Ahsan
0

Y concatenación múltiple:

from django import template
register = template.Library()


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

Y en plantilla:

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