Como concatenar strings em templates django?

189

Eu quero concatenar uma string em uma tag de modelo do Django, como:

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

Aqui shop_nameestá minha variável e eu quero concatenar isso com o restante do caminho.

Suponha que eu tenha shop_name=example.come quero que o resultado seja estendido shop/example.com/base.html.

Ahsan
fonte

Respostas:

379

Usar com:

{% with "shop/"|add:shop_name|add:"/base.html" as template %}
{% include template %}
{% endwith %}
Steven
fonte
2
Fiquei totalmente confuso com essa resposta, pois ela usa a tag de inclusão em vez da extensão, mas aparentemente funciona. Embora eu recomendasse a resposta de Ahsan, ela também funciona e é (na minha opinião) semanticamente mais correta e gera menos confusão.
Gitaarik
15
Isso pode funcionar, mas não deve ser considerado uma resposta geral para concatenar seqüências de caracteres em modelos de django. Veja stackoverflow.com/a/23783666/781695
usuário
Como diz o ditado na documentação do Django, "Strings que podem ser coagidas a números inteiros serão somadas, não concatenadas" Então, por exemplo, se você deseja concatenar as chaves primárias do objeto de modelo (pode ser útil para criar uma chave de cache exclusiva), isso não ocorre. trabalhos.
zen11625 25/09/2015
Eu acho que isso não escapa shop_name, então é perigoso.
Flimm
Esteja ciente, como já mencionado, isso funciona apenas com strings! Se você traduzir shop_nameantes de passá-lo para o contexto em uma visualização, get_context_dataverifique se está traduzido usando em ugettextvez de ugettext_lazy.
Kim
111

Não use addpara strings, você deve definir uma tag personalizada como esta:

Crie um arquivo: <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)

e depois use-o como @Steven diz

{% load <appname>_extras %}

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

Razão para evitar add:

De acordo com os documentos

Esse filtro tentará primeiro coagir os dois valores a números inteiros ... As seqüências que podem ser coagidas a números inteiros serão somadas, não concatenadas ...

Se as duas variáveis ​​forem inteiras, o resultado seria inesperado.

do utilizador
fonte
Não deveria ser @ register.filter (name = 'addstr')?
seddonym 26/08/14
6
Isso deve ser marcado como a melhor resposta, pois funciona corretamente com valores que podem ser coagidos pelo Python como números inteiros.
zen11625
2
Eu não sei porque você não é o único com o mais "para cima", porque é a sua resposta que é certo, o " add" sozinho apenas não usa str()em primeiro lugar e não funcionou em tudo para mim enquanto sua solução funciona perfeitamente
Olivier Pons
1
Sua resposta me salvou!
Ljubisa Livac
6
Lembre-se de carregar o filtro personalizado na parte superior do seu arquivo de modelo:{% load <appname>_extras %}
Susanne Peng
13

Eu mudei a hierarquia de pastas

/shop/shop_name/base.html Para /shop_name/shop/base.html

e então abaixo funcionaria.

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

Agora é capaz de estender a página base.html.

Ahsan
fonte
7

Consulte Concatenando strings em modelos do Django :

  1. Para versões anteriores do Django:

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

"Mary tinha um cordeirinho."

  1. Outro:

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

"Mary tinha um cordeirinho."

bing
fonte
3

Dê uma olhada no addfiltro .

Editar: você pode encadear filtros, para poder fazer isso "shop/"|add:shop_name|add:"/base.html". Mas isso não funcionará porque cabe à tag do modelo avaliar filtros nos argumentos, e a extensão não.

Eu acho que você não pode fazer isso nos modelos.

Daniel Hepper
fonte
isto não vai funcionar. Eu quero adicionar minha variável no meio do caminho.
Ahsan
adicionar filtro somado não concatenar de acordo com os documentos do django
Ahsan
Os documentos dizem que "strings que podem ser coagidas a números inteiros serão somadas". Outras seqüências são concatenadas. Mas isso realmente não importa de qualquer maneira, porque você não pode usar o filtro :(
Daniel Hepper
2

Dos documentos:

Essa tag pode ser usada de duas maneiras:

  • {% extends "base.html" %} (entre aspas) usa o valor literal "base.html" como o nome do modelo pai a ser estendido.
  • {% extends variable %}usa o valor da variável Se a variável for avaliada como uma string, o Django usará essa string como o nome do template pai. Se a variável for avaliada como um objeto Template, o Django usará esse objeto como modelo pai.

Parece que você não pode usar um filtro para manipular o argumento. Na visualização de chamada, é necessário instanciar o modelo ancestral ou criar uma variável de cadeia com o caminho correto e transmiti-la ao contexto.

Paulo Scardine
fonte
1

A resposta do @ error é fundamental, você deve usar uma tag de modelo para isso. No entanto, prefiro uma tag de modelo um pouco mais genérica que possa ser usada para executar qualquer tipo de operação semelhante 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 ''

e então você pode usá-lo assim em seu modelo:

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

Como o comentário menciona, essa tag de modelo é particularmente útil para informações repetíveis em um modelo, mas requer lógica e outras coisas que irão influenciar seus modelos ou nos casos em que você deseja reutilizar os dados passados ​​entre os modelos através de blocos:

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

e depois:

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

O crédito para a tag captureas é devido aqui: https://www.djangosnippets.org/snippets/545/

K3TH3R
fonte
1

Eu achei que trabalhar com a {% with %}tag era bastante complicado. Em vez disso, criei a seguinte tag de modelo, que deve funcionar em seqüências de caracteres e números inteiros.

from django import template

register = template.Library()


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

Em seguida, carregue a tag de modelo no seu modelo na parte superior, usando o seguinte:

{% load concat_string %}

Você pode usá-lo da seguinte maneira:

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

Pessoalmente, achei isso muito mais limpo para trabalhar.

Bono
fonte
0

Você não pode fazer manipulação de variáveis ​​nos modelos de django. Você tem duas opções: escreva sua própria tag de modelo ou faça isso em vista,

damir
fonte
meu requisito é fazê-lo apenas em modelos, para que a opção de visualizações não seja útil. Eu também tentei via tag de modelo personalizado, mas {% load concat%} deve após a tag {% extend ....%}. então como eu posso fazer isso agora?
Ahsan
Escreva uma tag extended_extends que aceite um formato de string e argumentos.
Paulo Scardine
você pode me dar um exemplo de como escrever tags personalizadas para as padrão?
Ahsan
0

extendsnão tem facilidade para isso. Coloque todo o caminho do modelo em uma variável de contexto e use-o ou copie a tag de modelo existente e modifique-a adequadamente.

Ignacio Vazquez-Abrams
fonte
thanx pela resposta! para a variável de contexto, tenho que definir o view.py, que não posso devido aos requisitos do meu projeto. e por favor dê o exemplo do segundo.
Ahsan
0

E concatenação múltipla:

from django import template
register = template.Library()


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

E no modelo:

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