Как повторить "блок" в шаблоне 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 %}