Djangoテンプレート構文と使用方法

Djangoテンプレート構文と使用方法

Djangoテンプレート言語の紹介(公式ドキュメントより)

Djangoのテンプレート言語は、機能性と使いやすさのバランスを取ることを目指しています。HTMLに慣れ親しんだ人にとっては、非常に快適な環境です。SmartyやJinja2などの他のテキストベースのテンプレート言語に触れたことがある場合は、Djangoのテンプレートにすぐに馴染めるでしょう。

哲学

プログラミングの背景がある場合、またはHTMLにプログラムコードを直接組み込む言語に慣れている場合は、Djangoテンプレートシステムが単にHTMLに埋め込まれたPythonではないことを覚えておく必要があります。これは表現のための設計であり、プログラムロジックのためのものではありません。

Djangoテンプレートシステムは、if、ブール値、forループなどのタグ機能を提供しますが、これらのタグは対応するPythonコードを単純に実行するわけではありません。テンプレートシステムは任意のPython式を実行しません。デフォルトでは、以下にリストされているマークアップ、フィルター、および構文のみがサポートされています(テンプレート言語に独自の拡張を追加することもできます)。

哲学

なぜXMLベースのテンプレート(ZopeのTALなど)ではなくテキストベースのテンプレートを使用するのか?私たちはDjangoのテンプレート言語がXML/HTMLテンプレートだけでなく、電子メール、JavaScript、CSVなどにも使用できることを望んでいます。テンプレート言語は、テキストベースのあらゆる形式に使用できます。

もう一つ:XMLを人間が編集するのは虐待です!

テンプレートとは?

テンプレートは単なるテキストファイルです。HTML、XML、CSVなど、あらゆるテキストベースの形式を生成できます。テンプレートには、評価時に値に置き換えられる変数が含まれており、変数にはテンプレートのロジックを制御するマークアップが含まれています。HTML内にテンプレート構文が含まれている場合、そのファイルはテンプレートと呼ばれます。

テンプレートのコメント

テンプレートのコメントは以下のように記述します:

{# {{ '10'|add_str:'5' }} #}
{# コメント内容 #}

変数 {{ 変数 }}

変数:構文は {{ }} です。括弧内にレンダリングする変数値を記述します。変数名は文字、数字、アンダースコアで構成されます。

コード例

# views.pyの関数
def template_test(request):
    name = '鋼蛋'
    age = 18
    hobby = ['歌', '踊り', 'ラップ', 'バスケットボール']
    empty_list = []
    empty_string = ''
    data = {
        'name': '鉄蛋',
        'age': 16,
        'hobby': hobby,
        'key': 'xxxxx'
    }
    empty_dict = {}
    return render(request, 'template_test.html', {
        'name': name,
        'age': age,
        'hobby': hobby,
        'empty_list': empty_list,
        'empty_string': empty_string,
        'data': data,
        'empty_dict': empty_dict
    })

# テンプレートファイル(template_test.html)
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>テンプレートテスト</title>
</head>
<body>
<p>{{ name }}</p>
<p>{{ age }}</p>
<p>{{ hobby }}</p>
<p>{{ empty_list }}</p>
<p>{{ empty_string }}</p>
<p>{{ data }}</p>
<p>{{ empty_dict }}</p>
</body>
</html>

ブラウザ表示結果

小結:{{ }}内にレンダリングする変数を記述します。標準的な記法は {{ 変数 }} です。バックエンドからパラメータが渡されない場合は表示されません。

ドット(.)の特別な意味

テンプレート言語ではドット(.)は特別な意味を持ち、オブジェクトの対応する属性値を取得するために使用されます。

例:インデックス、キー、属性、メソッド

# views.pyの関数
def template_test(request):
    numbers = [1, 2, 3, 4, 5]
    dictionary = {"name": "黒蛋"}

    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age

        def dream(self):
            return f"私は{self.name}、{self.age}歳です..."

    person1 = Person(name="鋼蛋", age=18)
    person2 = Person(name="狗蛋", age=17)
    person3 = Person(name="鉄蛋", age=16)

    person_list = [person1, person2, person3]
    return render(request, "template_test.html", {"numbers": numbers, "dictionary": dictionary, "person_list": person_list})

# テンプレートファイル
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>ドットのテスト</title>
</head>
<body>
    <p>{{ numbers.0 }}</p>   <!--リストの最初の要素-->
    <p>{{ dictionary.name }}</p><!--辞書のキー値-->
    <p>{{ person_list.0.name }}</p><!--オブジェクトのname属性-->
    <p>{{ person_list.0.dream }}</p><!--.操作はパラメータなしのメソッドを呼び出すことができます-->
</body>
</html>

小結

注:テンプレートシステムが(.)に遭遇した場合、以下の順序で検索します:

  1. 辞書内を検索
  2. 属性またはメソッド
  3. 数値インデックス(インデックスは負数にできません)

タグ {% %} - ロジック関連の操作

コード例

{% for item in items %}
    {% if condition %}
        <!--条件分岐-->
    {% elif another_condition %}
        <!--別の条件分岐-->
    {% else %}
        <!--条件が成立しない場合の処理-->
    {% endif %}
    <!--ifの終了-->
{% endfor %}
<!--forループの終了-->

if文のサポート

if文は and、or、==、>、<、!=、<=、>=、in、not in、is、is not の判断をサポートしています。

注意事項

Djangoのテンプレート言語は連続した判断をサポートしていません。以下の書き方もサポートしていません:

{% if a > b > c %}
    ...
{% endif %}

Djangoのテンプレート言語では、属性の優先度がメソッドよりも高くなります。

forループのパラメータ

変数 説明
`forloop.counter` 現在のループインデックス(1から開始)
`forloop.counter0` 現在のループインデックス(0から開始)
`forloop.revcounter` 現在のループの逆順インデックス(1で終了)
`forloop.revcounter0` 現在のループの逆順インデックス(0で終了)
`forloop.first` 現在のループが最初のループかどうか(ブール値)
`forloop.last` 現在のループが最後のループかどうか(ブール値)
`forloop.parentloop` このループの外側のループ

for ... empty

forタグには、指定されたグループが空の場合や見つからない場合に操作できる{% empty %}句がオプションで付属しています。

{% for person in person_list %}
    <p>{{ person.name }}</p>
{% empty %}
    <p>申し訳ありませんが、ここに人はいません</p>
{% endfor %}

フィルター

フィルターは変数の表示結果を変更するために使用されます。構文:{{ value|filter_name:parameter }}。':'の前後にはスペースを入れないでください。

割り算の判定 divisibleby:パラメータ

withの使用

中間変数を定義します(エイリアスを付け、with内でのみ有効)。

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

{% with business.employees.count as total %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

default - システムのデフォルト値

{{ value|default:"nothing"}}
valueの値が渡されない場合はnothingが表示されます。
注:TEMPLATESのOPTIONSでstring_if_invalid:'見つかりません'というオプションを追加できます。これはdefaultの機能を置き換えることができます。
(settings.pyで設定)

filesizeformat - ファイルサイズの人間的な表示

値を「人間が読める」ファイルサイズにフォーマットします(例:'13 KB', '4.1 MB', '102 bytes'など)。

{{ value|filesizeformat }}
valueが123456789の場合、出力は117.7 MBになります。

add - 「加算」

変数にパラメータを加算します。文字列はデフォルトでint型に変換を試み、変換できない場合は連結されます。

{{ value|add:"2" }}
valueが数字4の場合、出力結果は6になります。

{{ value|add:"hello" }}
valueが数字666の場合、出力結果は666helloになります。

{{ first|add:second }}
firstが[1,2,3]、secondが[4,5,6]の場合、出力結果は[1,2,3,4,5,6]になります。

lower - 小文字

{{ value|lower }}

upper - 大文字

{{ value|upper }}

title - タイトルケース

{{ value|title }}

ljust - 左揃え

"{{ value|ljust:"10" }}"

rjust - 右揃え

"{{ value|rjust:"10" }}"

center - 中央揃え

"{{ value|center:"15" }}"

length - 長さ

{{ value|length }}
valueの長さを返します。value=['a', 'b', 'c', 'd']の場合、4が表示されます。

slice - スライス

{{value|slice:"2:-1"}}

first - 最初の要素を取得

{{ value|first }}

last - 最後の要素を取得

{{ value|last }}

join - 文字列でリストを連結

Pythonのstr.join(list)と同じです。

{{ value|join:" // " }}

cut - 指定された文字列をすべて削除

valueが'i love you'の場合、出力は'iloveyou'になります。

{{ value|cut:' ' }}

truncatechars - 文字数で切り詰め(...もカウント)

文字列の文字数が指定された文字数より多い場合、切り詰められます。切り詰められた文字列は翻訳可能な省略記号シーケンス("...")で終わります。

{{ value|truncatechars:9}}

date - 日付フォーマット

# バックエンド
import datetime
def date_format(request):
    now = datetime.datetime.now()
    return render(request, 'date_format.html', {'now': now})

# テンプレート
{{ now|date:"Y-m-d H:i:s"}}   # 表示形式:年-月-日 時:分:秒

safe - XSS攻撃防止(エスケープの解除)

DjangoのテンプレートではHTMLタグやJS構文タグが自動的にエスケープされます。これは明らかにセキュリティのためです。しかし、場合によってはこれらのHTML要素がエスケープされないようにしたい場合があります。たとえば、コンテンツ管理システムを作成する場合、バックエンドで追加した記事は修飾されています。これらの修飾はFCKeditorのようなエディタでHTML修飾子が追加されたテキストである可能性があります。自動エスケープすると、HTMLタグを保護するソースファイルが表示されます。DjangoでHTMLの自動エスケープを無効にするには2つの方法があります。単一の変数の場合は、「|safe」フィルターを通じてDjangoにこのコードが安全であり、エスケープする必要がないことを伝えることができます。

カスタムフィルター

標準の組み込みフィルターでは開発要件を満たせない場合、カスタムフィルターを実装して機能を実現できます。

カスタムフィルターの流れ

  1. app下にtemplatetagsという名前のpythonパッケージを作成します。
  2. pythonでpyファイルを作成します。ファイル名は任意です(例:my_filters.py)。
  3. pyファイルに以下を記述します:
from django import template

register = template.Library()  # 固定の書き方、変更不可
  1. 関数とデコレータを記述します:
@register.filter
def add_str(value, arg):  # 最大2つのパラメータ
    return '{}-{}'.format(value, arg)
  1. ページコード:カスタムsimple_tagとfilterを使用するhtmlファイルで、前に作成したmy_tags.pyをインポートします。
{% load my_tags %}   # まずカスタムファイルmy_tagsをインポート
{{ name|add_str:age }}   # パラメータは2つしかありません。1つは変数name、もう1つは後ろのパラメータage

カスタム乗算フィルター multiply

# フィルター関数
@register.filter
def multiply(value, arg):
    return value * arg
    
# テンプレート
{% load my_tags %}
<p>{{ 6|multiply:'6' }}</p>
<p>{{ 6|multiply:6 }}</p>
<p>{{ '10'|multiply:5 }}</p>

カスタム除算フィルター divide

# フィルター関数
@register.filter
def divide(value, arg):
    return value / arg

# テンプレート
{% load my_tags %}
<p>{{ 6|divide:6 }}</p>
<p>{{ 6|divide:1 }}</p>

カスタム加算フィルター add

# フィルター関数
@register.filter
def add(value, arg):
    return value + arg

# テンプレート
{% load my_tags %}
<p>{{ 6|add:6 }}</p>
<p>{{ 6|add:0 }}</p>

カスタムタグ simpletag

カスタムフィルターとの違いは、より多くのパラメータを受け取れること、およびタグの参照に{{% %}}を使用することです。

# simple_tagのコード
@register.simple_tag(name="sum")
def sum_values(a, b, c):
    return "{} + {} + {}".format(a, b, c)

# simple tagの使用
{% load app01_demo %}
{# simple tag #}
{% sum "1" "2" "abc" %}

カスタムタグ inclusion_tag

主にHTMLコードのフラグメントを返すために使用されます(動的変数、ページネーション)。

appファイル下にpythonパッケージを作成

パッケージ名は必ずtemplatetagsにする

templatetags内に任意の.pyファイルを作成

関数を記述

HTMLページコード

# ページネーション表示コード
<nav aria-label="Page navigation">
  <ul class="pagination">
    <li>
      <a href="#" aria-label="Previous">
        <span aria-hidden="true">&laquo;</span>
      </a>
    </li>
    {% for i in num %}
        <li><a href="#">{{ i }}</a></li>
    {% endfor %}
    <li>
      <a href="#" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
      </a>
    </li>
  </ul>
</nav>

# ページ1
{% load my_tags %}
{% pagination 5 %}

# ページ2
{% load my_tags %}
{% pagination 1 %}

表示効果

まとめ:

  • カスタムフィルター filter:最大2つのパラメータを受け取り、呼び出し時は{{ filter }}を使用
  • カスタムタグ simpletag:カスタムフィルターとの違いは、より多くのパラメータを受け取り、タグの参照に{{% %}}を使用
  • カスタムタグ inclusion_tag:主にHTMLコードのフラグメントを返すために使用され、タグの参照に{{% %}}を使用

csrf_token - クロスサイトリクエストフォージェリ保護

ページのformタグ内に{% csrf_token %}を記述します。

静的ファイル関連

静的ファイルのエイリアスとファイルパスを結合し、エイリアスが変更されても影響を受けないようにします。

{% load static %}
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />

<script src="{% static "mytest.js" %}"></script>

{% load static %}
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}"></img>

テンプレートの継承

テンプレートとは?

通常のHTMLページ。テンプレートページはHTMLページの共通部分を処理し、冗長なコードを避け、重複したHTMLページの記述を減らし、コードの再利用性を高め、コードの修正を容易にします。

継承の書き方

子ページで、ページの最上部に以下の構文を使用してテンプレートを継承します。

{% extends 'base.html' %}

blockブロック

テンプレートで{% block xxx %}を使用して「ブロック」を定義します。子ページでは、テンプレート内のblock名を定義して、テンプレート内の対応する内容を置き換えます。

{% block ブロック名 %}
    # コンテンツ
{% endblock %}

子ページによるblockブロックの置き換え

注意点:

  1. {% extends 'base.html' %}は最初の行に記述します。前に内容があると表示されます。
  2. {% extends 'base.html' %}の'base.html'にはクォーテーションを付けます。さもないと変数として検索されます。
  3. 表示する内容はblockブロック内に記述します。
  4. 複数のblockブロックを定義し、css、jsブロックを定義します。

コンポーネント

よく使われるページコンテンツ(ナビゲーションバー、フッタ情報など)を個別のファイルに保存し、必要な場所で以下の構文を使用してインポートできます。

# 例:単独のhtmlファイル(navigation.html)
<nav aria-label="Page navigation">
  <ul class="pagination">
    <li>
      <a href="#" aria-label="Previous">
        <span aria-hidden="true">&laquo;</span>
      </a>
    </li>
    {% for i in num %}
        <li><a href="#">{{ i }}</a></li>
    {% endfor %}
    <li>
      <a href="#" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
      </a>
    </li>
  </ul>
</nav>

# 他のページでのインポート
{% include 'navigation.html' %}

タグ: Django テンプレート テンプレート言語

6月16日 22:02 投稿