Как повторить "блок" в шаблоне django
Я хочу использовать то же самое {%block %} дважды в одном шаблоне django. Я хочу, чтобы этот блок появлялся более одного раза в моем базовом шаблоне:
# 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 быстрое и грязное решение будет дублировать блок заголовок на 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:
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 core отклоняет этот билет, потому что они думают, что это не распространенный сценарий, однако я не согласен.
repeat block-простая и чистая реализация для этого: 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 parser проверяет синтаксис на обоих концах условного, не должен ли он проверять только условие истинности?)
# 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 включает только TRUTHY {% 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 %}
на веточка вы можете сделать это так:
# 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 %}