modelos django: incluem e estendem

108

Eu gostaria de fornecer o mesmo conteúdo em 2 arquivos base diferentes.

Então, estou tentando fazer isso:

page1.html:

{% extends "base1.html" %}
{% include "commondata.html" %}

page2.html:

{% extends "base2.html" %} 
{% include "commondata.html" %}

O problema é que não consigo usar extends e include. Existe alguma maneira de fazer isso? E se não, como posso realizar o acima?

commondata.html substitui um bloco que é especificado em base1.html e base2.html

O objetivo disso é fornecer a mesma página nos formatos pdf e html, onde a formatação é ligeiramente diferente. A pergunta acima, no entanto, simplifica o que estou tentando fazer, então, se conseguir uma resposta para isso, isso resolverá meu problema.

Net Citizen
fonte

Respostas:

110

Quando você usa a tag de template extends, está dizendo que o template atual estende outro - que é um template filho, dependente de um template pai. Django irá olhar para o seu template filho e usar seu conteúdo para preencher o pai.

Tudo o que você deseja usar em um template filho deve estar dentro de blocos, que o Django usa para preencher o pai. Se você quiser usar uma instrução include nesse template filho, você deve colocá-la dentro de um bloco, para que o Django faça sentido. Caso contrário, simplesmente não faz sentido e Django não sabe o que fazer com isso.

A documentação do Django tem alguns exemplos realmente bons de uso de blocos para substituir blocos no template pai.

https://docs.djangoproject.com/en/dev/ref/templates/language/#template-inheritance

Matt Howell
fonte
1
meu commondata.html tem o bloco definido nele. Mas não está substituindo o bloco do tempalte pai ... Se, em vez de fazer uma inclusão, eu escrever os dados exatos duas vezes em page1.html e page2.html, então é claro que funciona. Mas eu quero fatorar essa semelhança em commondata.html.
Net Citizen
Parece funcionar, lembro-me de tentar fazer isso, mas devo ter cometido um erro de digitação ou algo assim no momento que fez com que não funcionasse.
Net Citizen
1
veja minha resposta abaixo para saber por que não funcionou para mim da primeira vez, mas vou deixá-lo com a resposta aceita porque você respondeu a pergunta que fiz corretamente.
Net Citizen
80

Dos documentos do Django:

A tag de inclusão deve ser considerada como uma implementação de "renderizar este submodelo e incluir o HTML", não como "analisar este submodelo e incluir seu conteúdo como se fosse parte do pai". Isso significa que não há estado compartilhado entre os modelos incluídos - cada inclusão é um processo de renderização completamente independente.

Assim, o Django não pega nenhum bloco do seu commondata.html e não sabe o que fazer com os blocos externos do HTML renderizado.

podshumok
fonte
32

Isso deve funcionar para você: coloque a tag de inclusão dentro de uma seção de bloco.

page1.html:

{% extends "base1.html" %}

{% block foo %}
   {% include "commondata.html" %}
{% endblock %}

page2.html:

{% extends "base2.html" %}

{% block bar %}
   {% include "commondata.html" %}
{% endblock %}
Pavel Černý
fonte
1
Perfeito. Funciona para mim.
Trupti M Panchal
13

Mais informações sobre por que não estava funcionando para mim no caso de ajudar as pessoas futuras:

A razão pela qual não estava funcionando é que {% include%} no django não gosta de caracteres especiais, como apóstrofo extravagante. Os dados do modelo que estava tentando incluir foram colados do Word. Tive que remover manualmente todos esses caracteres especiais e então incluí-los com sucesso.

Net Citizen
fonte
3

Você não pode extrair blocos de um arquivo incluído em um modelo filho para substituir os blocos do modelo pai. No entanto, você pode especificar um pai em uma variável e ter o modelo base especificado no contexto.

Da documentação :

{% 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, Django usará aquele objeto como template pai.

Em vez de separar "page1.html" e "page2.html", coloque {% extends base_template %}no topo de "commondata.html". E então, em sua visão, defina base_templatecomo "base1.html" ou "base2.html".

esmeril
fonte
2

Adicionado para referência a futuras pessoas que encontrarem isso por meio do google: você pode querer olhar para a tag {% overextend%} fornecida pela biblioteca mezanino para casos como este.

Ted
fonte
1

Editar 10 de dezembro de 2015 : Conforme apontado nos comentários, o ssi está obsoleto desde a versão 1.8. De acordo com a documentação:

Esta tag tornou-se obsoleta e será removida no Django 1.10. Em vez disso, use a tag include.


Na minha opinião, a (melhor) resposta certa para essa pergunta é a de podshumok , pois explica por que o comportamento de include quando usado junto com a herança.

No entanto, fiquei um tanto surpreso que ninguém mencionou a tag ssi fornecida pelo sistema de modelos Django, que é projetado especificamente para inline, incluindo um pedaço de texto externo . Aqui, inline significa que o texto externo não será interpretado, analisado ou interpolado, mas simplesmente "copiado" dentro do modelo de chamada.

Por favor, consulte a documentação para mais detalhes (certifique-se de verificar sua versão apropriada do Django no seletor na parte inferior direita da página).

https://docs.djangoproject.com/en/dev/ref/templates/builtins/#ssi

Da documentação:

ssi
Outputs the contents of a given file into the page.
Like a simple include tag, {% ssi %} includes the contents of another file
 which must be specified using an absolute path  in the current page

Cuidado também com as implicações de segurança dessa técnica e também com a definição ALLOWED_INCLUDE_ROOTS necessária, que deve ser adicionada aos arquivos de configuração.

jose.angel.jimenez
fonte
1
Observe que, a partir de 1.8, o ssi se tornou obsoleto em favor da inclusão. https://docs.djangoproject.com/en/1.8/ref/templates/builtins/#std:templatetag-include
Tim S.