Jak powtórzyć "blok" w szablonie django

Chcę użyć tego samego {%block%} dwa razy w tym samym szablonie django. Chcę, aby ten blok pojawiał się więcej niż raz w moim szablonie bazowym:

# base.html
<html>
    <head>
        <title>{% block title %}My Cool Website{% endblock %}</title>
    </head>
    <body>
        <h1>{% block title %}My Cool Website{% endblock %}</h1>
    </body>
</html>

A następnie rozszerzyć:

# 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 %}

Dostanę wyjątek, ponieważ Django chce, aby blok pojawił się tylko raz:

TemplateSyntaxError at /

'pojawia się blok" tag z nazwą "title" więcej niż raz

Szybkim i brudnym rozwiązaniem byłoby powielenie bloku title into title1and title2:

# blog.html
{% extends 'base.html' %}
{% block title1 %}My Blog{% endblock %}
{% block title2 %}My Blog{% endblock %}
Ale to jest naruszenie zasady suchości. Byłoby to bardzo trudne, ponieważ mam wiele dziedziczących szablonów, a także dlatego, że nie chcę iść do piekła; -) Czy jest jakaś sztuczka lub obejście tego problemu? Jak mogę powtórzyć ten sam blok w szablonie, bez powielania całego kodu?
Author: niton, 2009-02-04

13 answers

Myślę, że użycie procesora kontekstowego jest w tym przypadku przesadą. Możesz to łatwo zrobić:

#base.html
<html>
    <head>
        <title>{% block title %}My Cool Website{% endblock %}</title>
    </head>
    <body>
        {% block content %}{% endblock %}
    </body>
</html>

A następnie:

# blog.html
{% extends 'base.html' %}
{% block content %}
    <h1>{% block title %}My Blog{% endblock %}</h1>
    Lorem ipsum here...
{% endblock %}

I tak dalej... Wygląda na suchą.

 63
Author: dqd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-05 07:56:56

Użyj wtyczki makr szablonów Django:

Http://www.djangosnippets.org/snippets/363/ (django

Lub

Https://gist.github.com/1715202 (django > = 1.4)

Then,

# 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>

I

# blog.html
{% extends 'base.html' %}
{% block title %}My Blog{% endblock %}
 79
Author: Ogre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-08 10:02:54

Prawdopodobnie nie chcesz używać bloku, ale po prostu użyj zmiennej:

# base.html
<html>
    <head>
        <title>{{ title|default:"My Cool Website" }}</title>
    </head>
    <body>
        <h1>{{ title|default:"My Cool Website" }}</h1>
    </body>
</html>

Następnie ustawiasz Tytuł przez kontekst.

 15
Author: Aaron Maenpaa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-04 12:34:15

Oto sposób, który odkryłem, próbując zrobić to samo Sam:

# 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 %}

Wymaga niestety dodatkowego pliku, ale nie wymaga podania tytułu z widoku.

 11
Author: Roman Starkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-27 14:39:41

Możesz użyć {% include subtemplate.html %} więcej niż raz. to nie to samo co klocki, ale robi sztuczkę.

 10
Author: Javier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-04 12:31:44

Tu jest jakaś dyskusja: http://code.djangoproject.com/ticket/4529 Oczywiście rdzenny zespół django odrzuca ten bilet, ponieważ uważają, że nie jest to często używany scenariusz, jednak nie zgadzam się.

Repeat block jest prostą i czystą implementacją tego: https://github.com/SmileyChris/django-repeatblock

Makra szablonów to kolejne, jednak autor wspomniał, że nie jest dokładnie sprawdzone przez: http://www.djangosnippets.org/snippets/363/

Użyłem repeatblocka.

 4
Author: Robert Mao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-23 05:47:20

Bazując na sugestii Van Gale ' a, możesz utworzyć znaczniki get I set, dodając następujące elementy templatetags.py plik:

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)

Następnie Ustaw wartości w jednym szablonie przez {% set foo %}put data here{% endset %} i pobierz je przez {% get foo %} w innym.

 3
Author: kieran hervold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-08 18:34:17

Oto lekkie rozwiązanie podobne do powyższego do_set i do_get odpowiedzi na znacznik szablonu. Django pozwala Ci przekazać cały kontekst szablonu do znacznika, który pozwala ci zdefiniować zmienną globalną.

Baza.html:

<!DOCTYPE html>
<html lang="en">
<head>
  {% block head %}
    <title>{{ title }}</title>
  {% endblock %}
</head>
<body>
  <h1>{{ title }}</h1>
</body>
</html>

Strona.html:

{% extends "base.html" %}

{% block head %}
  {% define 'title' 'Homepage | title' %}
  {{ block.super }}
{% endblock %}

Niestandardowy znacznik (mam pomysł tutaj: https://stackoverflow.com/a/33564990/2747924):

@register.simple_tag(takes_context=True)
def define(context, key, value):
    context.dicts[0][key] = value
    return ''

Również nie zapomnij {% load %} swoje niestandardowe tagi lub dodać je do opcji szablonu builtins lista więc nie musisz ładować ich w każdym szablonie. Jedynym ograniczeniem tego podejścia jest to, że {% define %} musi być wywołane z poziomu znacznika blokowego, ponieważ szablony potomne renderują tylko znaczniki blokowe pasujące do znaczników nadrzędnych. Nie wiem, czy można to obejść. Upewnij się również, że wywołanie define nadejdzie, zanim spróbujesz go oczywiście użyć.

 3
Author: manncito,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:07

Ja również natknąłem się na tę samą potrzebę powtarzania {% block %} w moich plikach szablonów. Problem polega na tym, że chcę, aby Django {%block %} było używane w obu przypadkach warunkowego Django i chcę, aby {%block %} było nadpisywalne przez kolejne pliki, które mogą rozszerzyć bieżący plik. (Więc w tym przypadku, to, co chcę jest zdecydowanie bardziej bloku niż zmiennej, ponieważ nie jestem technicznie ponownie go używać, to po prostu pojawia się na obu końcach warunkowe.

Na Problem:

Poniższy kod szablonu Django spowoduje błąd składni szablonu, ale myślę, że jest to poprawne "want", aby zdefiniowany {%block %} został ponownie użyty w warunku (tzn. dlaczego parser Django sprawdza składnię na obu końcach warunku, czy nie powinien tylko sprawdzać poprawności warunku?)

# 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 %}

Rozwiązanie:

Możesz użyć {% include%}, aby warunkowo wstawić {%block%} więcej niż jeden raz. Zadziałało mi to, ponieważ składnia Django checker zawiera tylko prawdziwe {%include %}. Zobacz wynik poniżej:

# 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 %}
 2
Author: potench,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-23 18:48:04

Jako aktualizacja dla każdego, kto się z tym zetknie, wziąłem wspomniany wyżej fragment i przekształciłem go w bibliotekę znaczników szablonów, django-macros, czyni makra potężniejszymi, a także implementuje powtarzający się wzorzec bloków jawnie: django-macros .

 2
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-03 06:01:00

Są na to dwa proste rozwiązania.

Najłatwiej jest umieścić swój tytuł w zmiennej kontekstowej. Można ustawić zmienną kontekstową w widoku.

Jeśli używasz czegoś takiego jak ogólne widoki i nie masz views.py do zdjęć, kotów itp. następnie możesz przejść drogą niestandardowego znacznika szablonu, który ustawia zmienną w kontekście .

Pójście tą drogą umożliwiłoby wykonanie czegoś takiego jak:

{% extends "base.html" %}
{% load set_page_title %}
{% page_title "My Pictures" %}
...

Potem w Twojej bazie.html:

...
{% block title %}{{ page_title }}{% endblock %}
...
<h1>{{ page_title }}</h1>
 1
Author: Van Gale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-04 12:45:29

Używam tej odpowiedzi , aby wszystko było suche.

{% extends "base.html" %}

{% with "Entry Title" as title %}
    {% block title %}{{ title }}{% endblock %}
    {% block h1 %}{{ title }}{% endblock %}
{% endwith %}
 1
Author: Christian Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:07

W gałązce możesz zrobić tak:

# 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 %}
 -3
Author: mars,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-01 06:22:28