web-dev-qa-db-ja.com

Djangoテンプレート:含まれている子テンプレートのブロックを拡張テンプレートで上書きする

誰かが以下の風変わりなテンプレート構造を処理する方法を知っているかどうか疑問に思っています:

### base.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">

<head>
  <title> {% block title %} Title of the page {% endblock %} </title>
</head>

<body>
  <header>
    {% block header %}
      {% include "base/header.html" %}
    {% endblock header %}
  </header>
  {% block content %}{% endblock %}
</body>

</html>

### base/header.html
<div id="menu-bar">
  {% block nav %}
    {% include "base/nav.html" %}
  {% endblock %}
</div>

### base/nav.html
<nav id="menu">
  <ul>
    <li>
      <a href="/profile/">My Profile</a>
    </li>
    <li>
      <a href="/favs/">My Favorites</a>
    </li>
    {% block extra-content %}{% endblock %}
  </ul>
</nav>

そして、問題の核心:


### app/somepage.html
{% extends "base.html" %}
{% block content %}
  <p>Content is overridden!</p>
{% endblock %}

{% block extra-content %}
  <p>This will not show up, though...</p>
{% endblock %}

{% block nav %}
  <p>Not even this.</p>
{% endblock %}

問題は、テンプレートを拡張するときに、親で宣言されたブロックのみをオーバーライドでき、子をオーバーライドできないことです。

Base.htmlを将来のすべての不測の事態をカバーする空の未使用のネストされたブロックの殻にすることができると思いますが、それでも適切にオーバーライドされますか?それが唯一の方法ですか?

Base.htmlの周りに双方向のinclude/extendsワークフローがある理由に疑問がある場合は、プロジェクト全体で使用したい多くのサブテンプレートがあります。ヘッダー、フッター、ナビゲーション、サイドバーなどです。これらはすべてサイト全体の構造は一貫していますが、多くの場合、サイトのサブディビジョン全体でこれらのサブテンプレートの一部のみが必要です。私のアイデアは、templates/baseフォルダーの下にサブテンプレートを定義し、templates/base-type1.html、templates/base-type2.htmlなどを他の場所で拡張できるようにすることでした。各タイプは必要なサブテンプレートのみを参照し、必要に応じてコンテンツを配置するためにそれらをオーバーライドします。

33
Chris Keele

これを解決するには、現在含まれているテンプレートを拡張し、現在含まれている基本テンプレートの代わりに拡張機能を含めます。

6
Marcin

withキーワードを include とともに使用して、含まれているテンプレートのコンテキストに変数を渡すことができることはあまり知られていないようです。これを使用して、含まれているテンプレートに含まれています:

# base.html
<html>
    <body>
        {% block header %}{% include "header.html" %}{% endblock %}
    </body>
</html>

# header.html
# some stuff here
<div id="header">
    <img src="logo.png">
    {% include nav_tmpl|default:"navigation.html" %}
</div>

# special_page.html (uses other navigation)
{% extends "base.html" %}
{% block header %}
    {% include "header.html" with nav_tmpl="special_nav.html" %}
    # you might also want to wrap the include in an 'if' tag if you don't want anything
    # included here per default 
{% endblock %}

このアプローチにより、少なくともブロックを上書きする目的でファイルを1つ追加する必要がなくなります。 withキーワードを使用して、インクルードのより大きな階層に値を渡すこともできます。

31

@ -Bernhard Vallantによって提案された ソリューションのより簡潔なバリアント

# base.html
<html>
    <body>
        {% block header %}{% include "header.html" %}{% endblock %}
    </body>
</html>

# header.html
# some stuff here
<div id="header">
    <img src="logo.png">
    {% include nav_tmpl|default:"navigation.html" %}
</div>

# special_page.html (uses other navigation)
{% extends "base.html" %}
{% block header %}
    {% with nav_tmpl="special_nav.html" %}
        {{ block.super }}
    {% endwith %}
{% endblock %}
12