djangoテンプレート:インクルードと拡張


108

2つの異なるベースファイル内に同じコンテンツを提供したいと思います。

だから私はこれをやろうとしている:

page1.html:

{% extends "base1.html" %}
{% include "commondata.html" %}

page2.html:

{% extends "base2.html" %} 
{% include "commondata.html" %}

問題は、エクステンドとインクルードの両方を使用できないように見えることです。それを行う方法はありますか?そうでない場合、どうすれば上記を達成できますか?

commondata.htmlは、base1.htmlとbase2.htmlの両方で指定されたブロックをオーバーライドします

これの目的は、同じページをpdfとhtml形式の両方で提供することですが、形式は少し異なります。上記の質問は、私が何をしようとしているのかを単純化していますが、答えが得られれば問題が解決します。

回答:


110

extendsテンプレートタグを使用すると、現在のテンプレートが別のテンプレートを拡張することになります-これは、親テンプレートに依存する子テンプレートです。Djangoは子テンプレートを調べ、そのコンテンツを使用して親に入力します。

子テンプレートで使用するものはすべてブロック内にある必要があります。Djangoはそれを使用して親を作成します。その子テンプレートでincludeステートメントを使用したい場合は、Djangoが理解できるように、それをブロック内に配置する必要があります。そうでなければ、それは意味をなさず、Djangoはそれをどうするかを知りません。

Djangoのドキュメントには、親テンプレートのブロックを置き換えるためにブロックを使用するいくつかの本当に良い例があります。

https://docs.djangoproject.com/en/dev/ref/templates/language/#template-inheritance


1
私のcommondata.htmlにはブロックが定義されています。しかし、それは親tempalteのブロックを置き換えていません...インクルードを行う代わりに、正確なデータをpage1.htmlとpage2.htmlの両方に2回書き込んだ場合、もちろんそれは機能します。しかし、私はcommondata.htmlにその共通性を取り除きたいと思います。
正味の市民

動作しているようですが、私はこれを試したのを覚えていますが、その時点でタイプミスや何かが原因で動作しなかったに違いありません。
正味市民、

1
最初にうまくいかなかった理由については、以下の私の回答を参照してください。私が正しく質問した質問に回答したので、承認された回答をそのまま残します。
正味市民、

80

Django docsから:

includeタグは、「このサブテンプレートを解析して、親の一部であるかのようにコンテンツを含める」ではなく、「このサブテンプレートをレンダリングしてHTMLを含める」の実装と見なす必要があります。つまり、インクルードされたテンプレート間で状態が共有されることはありません。各インクルードは完全に独立したレンダリングプロセスです。

そのため、Djangoはcommondata.htmlからブロックを取得せず、レンダリングされたhtmlの外側のブロックをどう処理するかを認識していません。


32

これはあなたのためのトリックをする必要があります:ブロックセクションの中にincludeタグを置きます。

page1.html:

{% extends "base1.html" %}

{% block foo %}
   {% include "commondata.html" %}
{% endblock %}

page2.html:

{% extends "base2.html" %}

{% block bar %}
   {% include "commondata.html" %}
{% endblock %}

1
完璧です。私のために働く。
Trupti M Panchal

13

それが将来の人々を助けるためにそれが私にとってうまくいかなかった理由の詳細:

機能しなかった理由は、djangoの{%include%}がファンシーアポストロフィのような特殊文字を好まないためです。挿入しようとしたテンプレートデータは、単語から貼り付けられました。これらの特殊文字をすべて手動で削除する必要があり、その後、正常に含まれました。


3

インクルードファイルから子テンプレートにブロックをプルして、親テンプレートのブロックを上書きすることはできません。ただし、変数で親を指定し、コンテキストでベーステンプレートを指定することができます。

ドキュメントから:

{%extends variable%}は変数の値を使用します。変数が文字列に評価される場合、Djangoはその文字列を親テンプレートの名前として使用します。変数がTemplateオブジェクトに評価される場合、Djangoはそのオブジェクトを親テンプレートとして使用します。

個別の「page1.html」と「page2.html」の代わりに、「commondata.html」{% extends base_template %}の上部に配置します。次に、ビューで、base_template「base1.html」または「base2.html」のいずれかに定義します。


2

google経由でこれを見つける将来の人々への参照用に追加:このような場合には、メザニンライブラリによって提供される{%overextend%}タグを確認することをお勧めします。


1

2015年12月10日の編集:コメントで指摘されているように、ssiはバージョン1.8以降非推奨です。ドキュメントによると:

このタグは廃止され、Django 1.10で削除されます。代わりにincludeタグを使用してください。


私の意見では、この質問に対する正しい(最良の)答えはpodshumokからのものです。これは、継承とともに使用したときにincludeの動作がなぜ使用されるのかを説明しているためです。

しかし、Djangoテンプレートシステムによって提供されるssiタグについて誰も言及しなかったことに少し驚きました。これは、外部のテキストを含むインライン向けに特別に設計されています。ここでは、インラインは、外部テキストが解釈、解析、または補間されるのではなく、呼び出しテンプレート内で単に「コピー」されることを意味します。

詳細については、ドキュメントを参照してください(ページの右下にあるセレクターで、適切なバージョンのDjangoを確認してください)。

https://docs.djangoproject.com/en/dev/ref/templates/builtins/#ssi

ドキュメントから:

ssi
Outputs the contents of a given file into the page.
Like a simple include tag, {% ssi %} includes the contents of another file
 which must be specified using an absolute path  in the current page

この手法のセキュリティへの影響と、設定ファイルに追加する必要がある必要なALLOWED_INCLUDE_ROOTS定義にも注意してください。


1
1.8の時点で、ssiは非推奨になり、インクルードになりました。https://docs.djangoproject.com/en/1.8/ref/templates/builtins/#std:templatetag-include
Tim S.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.