#python #django #django-templates #nested
#python #django #django-шаблоны #вложенные
Вопрос:
Это кажется довольно простой задачей, но, хотя я использую Django около года, я еще ни разу не сталкивался с этим сценарием.
Во многих шаблонах / веб-фреймворках наследование шаблонов работает немного по-другому, поскольку обычно оно ведет себя скорее как обертки, поэтому, если у вас есть childtemplate.html , parenttemplate.html, и grandparenttemplate.html , тогда окончательный рендеринг обычно выглядит примерно так:
grandparent header
parent header
child header
child content
parent content
parent footer
grandparent content
grandparent footer
Это не совсем так, как это работает в Django, но мне интересно, как это реализовать.
В частности, у меня есть свой «дочерний» шаблон, давайте просто скажем, что это foo.html
. foo.html
необязательно возвращает переменную parent_template
или значение по умолчанию равно «base.html «
{% extends parent_template|default:"base.html" %}
{% block content %}
I am a foo and my title is {{ foo.title }}
{% endblock content %}
Итак, здесь я сталкиваюсь с проблемой. Если parent_template
это шаблон, этот шаблон должен обернуть содержимое foo.html
, а затем поместить результат в base.html
:
{% extends "base.html" %}
{% something_magical_here %}
<div>parent header</div>
# content of foo.html
<div>parent footer</div>
{% end_something_magical_here %}
А затем в base.html
:
<html>
... snip ...
<div id="content">
{% something_else_magical %}
# content of parent_template rendering, or just foo.html if no parent_template given
{% end_something_else_magical %}
Который должен отображаться как
<html>
... snip ...
<div id="content">
<div>parent header</div>
I am a foo and my title is Bar
<div>parent footer</div>
если установлен parent_template и
<html>
... snip ...
<div id="content">
I am a foo and my title is Bar
если это не так.
Я надеюсь, что моя проблема ясна: мне нужно (необязательно) обернуть шаблон в родительский шаблон, а затем отправить результаты этого в base.html
шаблон.
Обычно может работать что-то подобное:
#foo.html
{% extends "parent.html" %}
{% block child_content %}
I am a foo and my title is {{ foo.title }}
{% endblock child_content %}
#parent.html
{% extends "base.html" %}
{% block content %}
parent header
{% block child_content %}{% endblock child_content %}
parent content
parent footer
#base.html
base header
{% block content %}{% endblock content %}
base content
base footer
Однако, поскольку parent_template может быть пустым, то иногда base.html будет получен только child_content
блок, а не сам content
блок.
Кроме того, я хотел бы иметь возможность делать это без необходимости создавать кучу подблоков (что, если я решу, что у foo
приложения должно быть свое собственное, /foo/base.html
которое затем вызывает /base.html
)?
Есть идеи?
Ответ №1:
тег extends template может принимать переменный аргумент.
итак:
base.html
{% block content %}
<p>BASE</p>
{% endblock %}
parent.html
{% extends "base.html" %}
{% block content %}
{{ block.super }}
<p>PARENT</p>
{% endblock %}
foo.html
{% extends ext_templ %}
{% block content %}
{{ block.super }}
<p>FOO</p>
{% endblock %}
использование базы:
return render_to_response('foo.html', {'ext_templ':'base.html'})
дает вам:
<p>BASE</p>
<p>FOO</p>
использование родительского:
return render_to_response('foo.html', {'ext_templ':'parent.html'})
дает вам:
<p>BASE</p>
<p>PARENT</p>
<p>FOO</p>
Редактировать:
один из способов обойти эту проблему, чтобы получить вложенные блоки, это:
base.html
{% block content %}
{% block top %}
<p>BASE START</p>
{% endblock %}
{% block bot %}
<p>BASE END</p>
{% endblock %}
{% endblock %}
parent.html
{% extends "base.html" %}
{% block top %}
{{ block.super }}
<p>PARENT</p>
{% endblock %}
{% block bot %}
<p>PARENT</p>
{{ block.super }}
{% endblock %}
foo.html
{% extends ext_templ %}
{% block top %}
{{ block.super }}
<p>FOO</p>
{% endblock %}
{% block bot %}
<p>FOO END</p>
{{ block.super }}
{% endblock %}
Другой метод, который я могу придумать, — обернуть блоки {% if ext_templ == 'parent.html' %}
тегом, но это кажется не очень сухим. Мне любопытно посмотреть, как другие люди реагируют на вложенные блоки.
Комментарии:
1. Я знаю о возможности отправки переменных аргументов, и действительно, это то, что я делаю. И мне нужно, чтобы
<p>BASE START</p><p>PARENT START</p><p>FOO</p><p>PARENT END</p><p>BASE END</p>
so{{ block.super }}
не сокращал его, поскольку он помещает содержимое только наверх.2. Я поддерживаю ваш ответ, поскольку считаю идею интересной, но это все еще не полный ответ. Я определенно хотел бы увидеть ответы других людей, если таковые появятся. 🙂
3. django необходимо разобраться с множественным наследованием шаблонов, иначе как вы должны выглядеть для своего сайта. Из-за этого мой сайт выглядит не очень СУХИМ
Ответ №2:
- base.html
{% block content %}
<p>Grand Parent file</p>
{% endblock %}
- parent.html
{% extends 'base.html' %}
{% block content %}
{% include 'grandchild1.html' %}
{% include 'grandchild2.html' %}
{% endblock %}
3.1. grandchild1.html
<div>Hello I'm grandchild 1</div>
3.2 grandchild1.html
<div>Hello I'm grandchild 2</div>
Таким образом, вы можете вложить до любого уровня. запишите каждый компонент в разделы в отдельных файлах .html.
Включите их в parent.html или в любые другие файлы.
Ответ №3:
У меня было три шаблона: gparent, parent и gchild. Затем я протестировал gparent и gchild следующим образом:
у gparent был следующий тег block hn. gchild расширяет gparent. Нет ссылки на parent.
{% block hn %}
Can you see me? # 1 naked text in the html, treated as a string.
{{ "No, I cant see you." }} # 2 A string literal in the variable template brace.
{% endblock hn %}
Обе эти строки между тегами отображаются в дочернем окне на экране. Когда последний не был строкой, Django выдал ошибку синтаксического анализа. Это потому, что внутри двойных фигурных скобок Django ожидает переменную или что-то вроде этого строкового литерала, который он может вычислить.
Когда я добавил блок hn и это содержимое в gchild, я увидел только содержимое блока hn gchild.
{% block hn %}
Now I have my own hn block
{% endblock hn %}
Затем я повторил этот тест, оставив блок hn gchild на месте, но удалив содержимое:
{% block hn %}
{% endblock hn %}
Пустой, но присутствующий блок hn на gchild заблокировал (переопределил) содержимое hn блока gparent.
Для этого следующего теста я вставил parent между gparent и gchild. Теперь parent расширяет gparent, а gchild расширяет parent.
{% block metadata %}
{{ "You must eat your metadata to grow big and strong" }}
{% endblock metadata %}
У родительского элемента теперь есть этот тег метаданных блока, который не присутствует ни в gparent, ни в gchild.
Это содержимое не отображалось.
Затем я вложил метаданные блока внутрь блока hn в родительский. у gparent все еще есть две строки, которые мы тестировали из блока hn минуту назад. у gchild есть пустой блок hn.
Как и раньше, ничего не отображалось.
Теперь я удалю блок hn из gchild:
You must eat your metadata to grow big and strong
Итак, вы можете добавить новый тег блока, которого нет в более раннем поколении шаблонов, при условии, что он полностью вложен в доступный блок, который определяет предок.
Затем поколение sandwich передаст этот новый тег и его содержимое дочернему элементу, который отобразит его, если дочерний элемент не заблокирует (переопределит) его.
Помните, что документы описывают содержимое между тегами как пробел, который нужно заполнить. Если у дочернего элемента нет тега, пробел заполняется родительским. Это то, что делает родительское содержимое по умолчанию. Именно поэтому большинство базовых шаблонов содержат верхний и нижний колонтитулы, навигацию и стиль, которые вы хотите использовать по всему сайту. Но с тем же тегом у дочернего элемента дочерний элемент сам заполняет пробел. Опять же, вот почему дочерний элемент может иметь свой собственный тег заголовка блока, даже если он вложен внутри html, который обычно находится внутри заголовка родительского блока, или как бы вы его ни называли.
Я действительно боролся с этим, когда впервые изучал Django, потому что я всегда хотел делать сумасшедшие вещи, такие как
{% block first %}
{% block second %}
{% endblock first %}
{% endblock second %}
Это нигде не будет работать.