Как повторить "блок" в шаблоне django
Я хочу использовать то же самое {%block%} два раза в один и тот же шаблон Джанго. Я хочу, чтобы этот блок появлялся более одного раза в моем базовом шаблоне:
# base.html
<html>
<head>
<title>{% block title %}My Cool Website{% endblock %}</title>
</head>
<body>
<h1>{% block title %}My Cool Website{% endblock %}</h1>
</body>
</html>
а затем расширить его:
# blog.html
{% extends 'base.html' %}
{% block title %}My Blog{% endblock %}
# pictures.html
{% extends 'base.html' %}
{% block title %}My Pictures{% endblock %}
# cats.html
{% extends 'base.html' %}
{% block title %}My Cats{% endblock %}
я получу исключение, так как Django хочет, чтобы блок появлялся только один раз:
TemplateSyntaxError at /
появляется тег 'block' С именем ' title
не раз
A быстрое и грязное решение будет дублировать блок title на title1 и title2:
# blog.html
{% extends 'base.html' %}
{% block title1 %}My Blog{% endblock %}
{% block title2 %}My Blog{% endblock %}
но это же нарушение сухой принципе. Это было бы очень сложно, так как у меня много наследующих шаблонов, а также потому, что я не хочу идти в ад ; -)
есть ли какой-то трюк или обойти эту проблему? Как я могу повторить тот же блок в моем шаблоне, не дублируя все код?
13 ответов:
Я думаю, что использование контекстного процессора в этом случае является излишним. Вы можете легко сделать это:
#base.html <html> <head> <title>{% block title %}My Cool Website{% endblock %}</title> </head> <body> {% block content %}{% endblock %} </body> </html>и затем:
# blog.html {% extends 'base.html' %} {% block content %} <h1>{% block title %}My Blog{% endblock %}</h1> Lorem ipsum here... {% endblock %}и так далее... Выглядит как сухой-совместимый.
используйте плагин Django template macros:
http://www.djangosnippets.org/snippets/363/ (django
или
https://gist.github.com/1715202 (django > = 1.4)
затем,
# base.html {% macro title %} {% block title %}My Cool Website{% endblock %} {% endmacro %} <html> <head> <title>{% usemacro title %}</title> </head> <body> <h1>{% usemacro title %}</h1> </body> </html>и
# blog.html {% extends 'base.html' %} {% block title %}My Blog{% endblock %}
вы, вероятно, не хотите использовать блок, а просто использовать переменную:
# base.html <html> <head> <title>{{ title|default:"My Cool Website" }}</title> </head> <body> <h1>{{ title|default:"My Cool Website" }}</h1> </body> </html>затем вы устанавливаете заголовок через контекст.
вот как я обнаружил, когда пытался сделать то же самое сам:
# base_helper.html <html> <head> <title>{% block _title1 %}{% endblock %}</title> </head> <body> <h1>{% block _title2 %}{% endblock %}</h1> </body> </html> # base.html {% extends "base_helper.html" %} # Copy title into _title1 & _title2, using "My Cool Website" as a default. {% block _title1 %}{% block _title2 %}{% block title %}My Cool Website{% endblock %}{% endblock %}{% endblock %}требуется дополнительный файл к сожалению, но не требует, чтобы вы передали заголовок из представления.
можно использовать
{% include subtemplate.html %}несколько раз. это не то же самое, что блоки, но делает трюк.
есть некоторые обсуждения здесь: http://code.djangoproject.com/ticket/4529 Очевидно, что основная команда django отвергает этот билет, потому что они думают, что это не общий используемый сценарий, однако я не согласен.
повторите блок простая и чистая реализация для этого: https://github.com/SmileyChris/django-repeatblock
шаблон макросов еще один, однако автор упомянул, что это не тщательно проверенный: http://www.djangosnippets.org/snippets/363/
Я использовал repeatblock.
основываясь на предложении Ван Гейла, вы можете создать get и установить теги, добавив следующее в свой templatetags.py файл:
register = template.Library() Stateful = {} def do_set(parser, token): _, key = token.split_contents() nodelist = parser.parse(('endset',)) parser.delete_first_token() # from the example -- why? return SetStatefulNode(key,nodelist) class SetStatefulNode(template.Node): def __init__(self, key, nodes): Stateful[key] = nodes def render(self, context): return '' register.tag('set', do_set) def do_get(parser, token): tag_name, key = token.split_contents() return GetStatefulNode(key) class GetStatefulNode(template.Node): def __init__(self, key): self.key = key def render(self, context): return ''.join( [x.render(context) for x in Stateful[self.key]] ) register.tag('get', do_get)затем установите значения в одном шаблоне через
{% set foo %}put data here{% endset %}и получить их через{% get foo %}в другой.
вот легкое решение, похожее на выше
do_setиdo_getтег шаблона ответа. Django позволяет передать весь контекст шаблона в теге, который может позволить вам определить глобальную переменную.базы.html:
<!DOCTYPE html> <html lang="en"> <head> {% block head %} <title>{{ title }}</title> {% endblock %} </head> <body> <h1>{{ title }}</h1> </body> </html>
Я тоже столкнулся с такой же потребностью в повторном {%block%} В моих файлах шаблонов. Проблема в том, что я хочу, чтобы Django {% block %} использовался в любом случае условного Django, и я хочу, чтобы {% block %} был перезаписан последующими файлами, которые могут расширить текущий файл. (Так что в этом случае то, что я хочу, определенно больше блока, чем переменной, потому что я технически не использую его повторно, он просто появляется на любом конце условного.
в Проблема:
следующий код шаблона Django приведет к синтаксической ошибке шаблона, но я думаю, что это допустимое "хочу", чтобы определенный {% block %} повторно использовался в условном (т. е. почему синтаксический анализатор Django проверяет синтаксис на обоих концах условного, не должен ли он проверять только условие истинности?)
# This example shows a {{ DEBUG }} conditional that loads # Uncompressed JavaScript files if TRUE # and loads Asynchronous minified JavaScript files if FALSE. # BASE.html {% if DEBUG %} <script src="{{MEDIA_URL}}js/flatfile.1.js"></script> <script src="{{MEDIA_URL}}js/flatfile.2.js"></script> <script src="{{MEDIA_URL}}js/flatfile.3.js"></script> <script type="text/javascript"> {% block page_js %} var page = new $site.Page(); {% endblock page_js %} </script> {% else %} <script type="text/javascript"> // load in the PRODUCTION VERSION of the site // minified and asynchronosly loaded yepnope([ { load : '{MEDIA_URL}}js/flatfiles.min.js', wait : true, complete : function() { {% block page_js %} // NOTE THE PAGE_JS BLOCK var page = new $site.Page(); {% endblock page_js %} } } )]; </script> {% endif %} # ABOUT.html {% extends 'pages/base.html' %} {% block page_js %} var page = new $site.Page.About(); {% endblock page_js %}Решение:
можно использовать {% include %} для условной вставки {%block %} Несколько раз. Это сработало для я, потому что проверка синтаксиса Django включает только истину {% include %}. Смотрите результат ниже:
# partials/page.js {% block page_js %} var page = new $site.Page(); {% endblock %} # base.html {% if DEBUG %} <script src="{{MEDIA_URL}}js/flatfile.1.js"></script> <script src="{{MEDIA_URL}}js/flatfile.2.js"></script> <script src="{{MEDIA_URL}}js/flatfile.3.js"></script> <script type="text/javascript"> {% include 'partials/page_js.html' %} </script> {% else %} <script type="text/javascript"> yepnope([ { load : '{MEDIA_URL}}js/flatfiles.min.js', wait : true, complete : function() { {% include 'partials/page_js.html' %} } } )]; </script> {% endif %}
в качестве обновления для всех, кто сталкивается с этим, я взял фрагмент, упомянутый выше, и превратил его в библиотеку тегов шаблона, django-macros, делает макросы более мощными, а также реализует повторяющийся шаблон блока явно:django-макросы.
есть два простых решения этой проблемы.
проще всего поместить заголовок в контекстную переменную. Вы должны установить переменную контекста в своем представлении.
Если вы используете что-то вроде родовой вид и нет views.py для фотографий, кошек и т. д. тогда вы можете пойти по пути пользовательский шаблон тега, который устанавливает переменную в контексте.
этот маршрут позволит вам сделать что-то вроде:
{% extends "base.html" %} {% load set_page_title %} {% page_title "My Pictures" %} ...затем в ваша база.html:
... {% block title %}{{ page_title }}{% endblock %} ... <h1>{{ page_title }}</h1>
Я использую ответ сохранить вещи сухими.
{% extends "base.html" %} {% with "Entry Title" as title %} {% block title %}{{ title }}{% endblock %} {% block h1 %}{{ title }}{% endblock %} {% endwith %}
In веточка вы можете сделать что-то типа:
# base.html <html> <head> <title>{{ block('title') }}</title> </head> <body> <h1>{{ block('title') }}</h1> </body> </html> # blog.html {% extends 'base.html' %} {% block title %}My Blog{% endblock %} # pictures.html {% extends 'base.html' %} {% block title %}My Pictures{% endblock %} # cats.html {% extends 'base.html' %} {% block title %}My Cats{% endblock %}
Comments