шаблоны django: включают и расширяют

109

Я хотел бы предоставить один и тот же контент в двух разных базовых файлах.

Итак, я пытаюсь сделать это:

page1.html:

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

page2.html:

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

Проблема в том, что я не могу использовать как extends, так и include. Есть ли способ сделать это? А если нет, то как я могу это сделать?

commondata.html переопределяет блок, указанный как в base1.html, так и в base2.html.

Это делается для того, чтобы предоставить одну и ту же страницу в формате pdf и html, где форматирование немного отличается. Приведенный выше вопрос упрощает то, что я пытаюсь сделать, поэтому, если я смогу получить ответ, он решит мою проблему.

Net Citizen
источник

Ответы:

110

Когда вы используете тег extends template, вы говорите, что текущий шаблон расширяет другой - что это дочерний шаблон, зависящий от родительского шаблона. Django будет смотреть на ваш дочерний шаблон и использовать его содержимое для заполнения родительского.

Все, что вы хотите использовать в дочернем шаблоне, должно находиться внутри блоков, которые Django использует для заполнения родительского шаблона. Если вы хотите использовать оператор include в этом дочернем шаблоне, вы должны поместить его в блок, чтобы Django понял его смысл. В противном случае это просто не имеет смысла, и Django не знает, что с этим делать.

В документации Django есть несколько действительно хороших примеров использования блоков для замены блоков в родительском шаблоне.

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

Мэтт Хауэлл
источник
1
В моем commondata.html определен блок. Но он не заменяет родительский блок tempalte ... Если вместо включения я дважды напишу точные данные как в page1.html, так и в page2.html, то, конечно, это сработает. Но я хочу исключить эту общность в commondata.html.
Net Citizen
Кажется, работает, я помню, как пробовал это, но в то время у меня, должно быть, была опечатка или что-то еще, из-за чего это не сработало.
Net Citizen
1
см. мой ответ ниже, почему это не сработало для меня в первый раз, я оставлю вам принятый ответ, потому что вы правильно ответили на вопрос, который я задал.
Net Citizen
80

Из документов Django:

Тег include следует рассматривать как реализацию «отрисовать этот подшаблон и включить HTML», а не как «проанализировать этот подшаблон и включить его содержимое, как если бы оно было частью родителя». Это означает, что между включенными шаблонами нет общего состояния - каждое включение - это полностью независимый процесс рендеринга.

Таким образом, Django не захватывает блоки из вашего commondata.html и не знает, что делать с визуализированными внешними блоками HTML.

подшумок
источник
32

Это должно помочь вам: поместите тег include внутри блока.

page1.html:

{% extends "base1.html" %}

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

page2.html:

{% extends "base2.html" %}

{% block bar %}
   {% include "commondata.html" %}
{% endblock %}
Павел Черный
источник
1
Отлично. Работает для меня.
Trupti M Panchal
13

Подробнее о том, почему у меня это не сработало на случай, если это поможет будущим людям:

Причина, по которой он не работает, заключается в том, что {% include%} в django не любит специальные символы, такие как причудливый апостроф. Данные шаблона, которые я пытался включить, были вставлены из слова. Мне пришлось вручную удалить все эти специальные символы, а затем он успешно включился.

Net Citizen
источник
3

Вы не можете вставлять блоки из включенного файла в дочерний шаблон, чтобы переопределить блоки родительского шаблона. Однако вы можете указать родительский элемент в переменной и указать базовый шаблон в контексте.

Из документации :

{% extends variable%} использует значение переменной. Если переменная вычисляется как строка, Django будет использовать эту строку как имя родительского шаблона. Если переменная оценивается как объект Template, Django будет использовать этот объект в качестве родительского шаблона.

Вместо отдельных "page1.html" и "page2.html" поместите {% extends base_template %}вверху "commondata.html". А затем, на ваш взгляд, определите base_templateзначение «base1.html» или «base2.html».

Эмери
источник
2

Добавлено для справки для будущих людей, которые найдут это через Google: вы можете посмотреть на тег {% overextend%}, предоставляемый библиотекой мезонина для подобных случаев.

Тед
источник
1

Изменить 10 декабря 2015 года : как указано в комментариях, ssi устарел с версии 1.8. По документации:

Этот тег устарел и будет удален в Django 1.10. Вместо этого используйте тег include.


На мой взгляд, правильный (лучший) ответ на этот вопрос - от podshumok , поскольку он объясняет, почему поведение include при использовании вместе с наследованием.

Однако я был несколько удивлен, что никто не упомянул тег ssi, предоставляемый системой шаблонов Django, который специально разработан для встраивания, включая внешний фрагмент текста . Здесь inline означает, что внешний текст не будет интерпретироваться, анализироваться или интерполироваться, а просто «копируется» внутри вызывающего шаблона.

Пожалуйста, обратитесь к документации для получения дополнительной информации (не забудьте проверить свою версию Django в селекторе в нижней правой части страницы).

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

Из документации:

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

Остерегайтесь также последствий для безопасности этого метода, а также необходимого определения ALLOWED_INCLUDE_ROOTS, которое необходимо добавить в ваши файлы настроек.

jose.angel.jimenez
источник
1
Обратите внимание, что с версии 1.8 ssi устарел в пользу Include. https://docs.djangoproject.com/en/1.8/ref/templates/builtins/#std:templatetag-include
Тим С.