CODE‎ > ‎GAE‎ > ‎

Django模板語言

Templates

{% extends "base_generic.html" %} {% block title %}{{ section.title }}{% endblock %} {% block content %}
< h1 > {{ section.title }} < / h1 > 
 
{% for story in story_list %}
< h2 > 
  < a  href = "{{ story.get_absolute_url }}" > 
    {{ story.headline|upper }}
  < / a > 
< / h2 > 
< p > {{ story.tease|truncatewords :"100" }} < / p > 
{% endfor %} {% endblock %}

Variables

變量的形式: {{ variable }}. 當模板引擎遇到一個變量時,就會對變量求值,並在變量所在的位置用變量的值取代變量名,然後輸出.使用句點(.) 可以訪問變量的屬性

當模板系統遇到句點, 它會按順序嘗試進依次查詢:

  • Dictionary lookup
  • Attribute lookup
  • Method call
  • List-index lookup

在上面的例子中, {{ section.title }} 會被section 對象的title 屬性替換.

如果你用到的一個變量不存在,模板系統會插入一個值:TEMPLATE_STRING_IF_INVALID ,這個值在settings 中定義, 默認設置是一個空的字符串.

過濾器

通過使用過濾器,可以定制變量的顯示格式。

過濾器的形式: {{ name|lower }}. 這將顯示{{ name }} 變量通過lower 過濾後的值. 它將文本轉換為小寫. 使用管道符號(|) 應用一個過濾器.

過濾器可以“鏈接”. 一個過濾器的輸入作為下一個過濾器的輸入: {{ text|escape|linebreaks }} 是一個常用過濾器組合,用於將文本內容轉義然後將換行轉換成<p > 標籤.

有些過濾器能接受參數. 一個帶有參數的過濾器看起來這樣: {{ bio|truncatewords:"30" }}. 它用來顯示bio 變量的前30 個. 過濾器參數總是帶有比引號. 下文中的內建過濾器參考描述了所有的內建過濾器.

標籤

標籤看起來這樣: {% 標籤%}. 標籤比起變量來複雜的多: 它負責在輸出中創建一些文本,執行循環或邏輯分支, 裝入額外信息以供後面的模板變量使用等等.

有些標籤要求有開始標記和結束標記(也就是{% tag %} … 標籤內容… {% endtag %}). 下文中的內建標籤參考描述了所有的內建標籤.你也可以創建你自己的標籤, 如果你會寫Python 代碼的話.

模板繼承

Django 模板引擎最強大的— 也是最複雜的— 部分是模板繼承. 模板繼承允許你建立一個基本的“骨架” 模板, 它包含你所有最常用的站點元素並定義了一些可以被子模板覆蓋的塊 .

通過下面的例子你很容易理解模板繼承:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 < html xmlns = "http ://www.w3.org/1999/xhtml" xml: lang = "en"  lang = "en" > 
< head > 
    < link  rel = "stylesheet"  href = "style.css"  / > 
    < title > {% block title %}My amazing site{% endblock %} < / title > 
< / head > 
 
< body > 
    < div  id = "sidebar" > 
        {% block sidebar %}
        < ul > 
            < li >< a  href = "/" > Home < / a >< / li > 
            < li >< a  href = "/blog/" > Blog < / a >< / li > 
        < / ul > 
        {% endblock %}
    < / div > 
 
    < div  id = " content" > 
        {% block content %}{% endblock %}
    < / div > 
< / body > 
< / html >

我們稱它為base.html,定義了一些簡單的 HTML 骨架文檔,你可以把它用到一些簡單兩列的網頁上. “子”模板的任務就是用內容填寫這些空白的內容塊.

在這個例子裡, {% block %} 標籤定義了三個子模板要填寫的block . 所有的block 標籤告訴模板引擎,模板的這些部分可以被子模板覆蓋.

一個子模板類似下面這樣:

{% extends "base.html" %} {% block title %}My amazing blog{% endblock %} {% block content %} {% for entry in blog_entries %}
    < h2 > {{ entry.title }} < / h2 > 
    < p > {{ entry.body }} < / p > 
{% endfor %} {% endblock %}

這裡的{% extends %} 標籤是最關鍵的. 它告訴模板引擎這個模板“擴展” 了另一個模板. 當模板系統要應用該模板時,首先它會去尋找父模板–在這裡是“base. html” .

模板引擎會注意到在base.html 裡有三個block 並用子模板的相關內容替換這些block. 用blog_entries 裡的值填寫父模板之後, 最後的輸出可能看起來像這樣:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 < html xmlns = "http ://www.w3.org/1999/xhtml" xml: lang = "en"  lang = "en" > 
< head > 
    < link  rel = "stylesheet"  href = "style.css"  / > 
    < title > My amazing blog < / title > 
< / head > 
 
< body > 
    < div  id = "sidebar" > 
        < ul > 
            < li >< a  href = "/" > Home < / a >< / li > 
            < li >< a  href = "/blog/" > Blog < / a >< / li > 
        < / ul > 
    < / div > 
 
    < div  id = "content" > 
        < h2 > Entry one < / h2 > 
        < p > This is my first entry. < / p > 
 
        < h2 > Entry two < / h2 > 
        < p > This is my second entry. < / p > 
    < / div > 
< / body > 
< / html >

注意由於子模板並未定義sidebar block, 父模板中的值就被保留.

對模板的繼承層數,Django未做任何限制. 常用的一種模板繼承方法是如下的三層:

  • 創建一個``base.html`` 模板,用它表現站點主要的外觀。
  • 為站點的每個section 創建一個``base_SECTIONNAME.html`` 模板。 比如``base_news.html``,``base_sport.html``等等, 這些模板擴充了``base.html`` 並包括section 特有的樣式和設計。
  • 為每種類型的頁面創建一個獨立的模板,比如一篇新聞稿或者一個博客,這些模板擴展了相應的section 模板。

這種方式能夠最大程度的重用代碼並能很容易的擴充內容及共享內容區塊,比如section-範圍的導航。

下面是使用模板繼承的一些小技巧:

  • 如果你在模板中使用了``{% extends %}`` ,那麼它必須是這個模板中的第一個模板tag ,否則它就不工作。
  • 在父模板中``{% block %}`` 標籤雖然不是越多越好,總得來說多比少好. 記住,子模板不需要定義所有的parent block, 因此你可以先定義一系列blocks並填入合理的默認值, 然後定義那些你以後才需要的block. It's better to have more hooks than fewer hooks.
  • 如果發現在一堆模板文件中重複定義相同的內容, 就意味著需要將這些內容放到父模板的一個``{% block %}`` 中去.
  • 如果你需要在子模板中引用父模板中的block 的內容,使用``{{ block.super }}``變量. 這在你希望在父模板的內容之後添加一些內容時會很有用.(你不必完全覆蓋父模板的內容.)

最後, 提醒你不能在一個模板文件中定義多個相同名字的{% block %} 標籤.

使用內建參考

Django 自帶的admin site 內建一個當前站點的所有模板標籤及過濾器的參考. 要查閱這個參考, 進入admin 站點,然後點擊頁面右上角的“Documentation” 鏈接(如果你的語言選擇的是中文,你會看到一個“文檔” 鏈接)..

這個參考分為四大部分:tags, filters, models, 和views.

tags 和filters 部分描述了所有的內建標籤(事實上, 下文中的標籤和過濾器參考直接來自那些頁面)和所有自定義標籤或過濾器庫(如果有的話).

views頁是最有價值的.你站點中的每個 URL 都有一個入 ​​口在這兒,點擊這個 URL 你會看到:

生成該頁面的view 函數的名字該view 功能的一個簡短的描述. 該view 的context, 或者該view 對應模板中的可用變量列表模板的名字,或該模板使用到的模板名字每個view 文檔頁還有一個bookmarklet , 使用它你可以任意頁跳回到這個view 頁.

由於Django 站點通常會用到數據庫對象, 文檔頁的models 小節描述了系統中每個對象的類型及那個對象的所有可用字段.

總得來說, 文檔頁會告訴你給定模板的每個標籤, 每個過濾器,每個變量和對象的細節信息.

自定義標籤及過濾器庫

某些應用提供自定義標籤和過濾器庫. 要在一個模板中訪問它們, 使用{% load %} 標籤:

{% load comments %}
{% comment_form for blogs.entries entry.id with is_public yes %}

在上面這個例子裡, load 標籤載入comments 標籤庫, 之後comment_form 標籤才能使用. 參考你的admin 界面的文檔部分你會發現一個自定義庫的列表. {% load %} 標籤可接受空隔分隔的多個庫的名字作為參數. 比如:

{% load comments i18n %}

自定義庫及模板繼承

當你載入一個自定義標籤或過濾器庫, 只有當前模板可以使用這些標籤/過濾器— 繼承鏈中不論是父模板還是子模板都不能使用使用這些標籤和過濾器.

舉例來說, 如果一個模板foo.html 內有{% load comments %} 指令, 一個子模板(也就是一個模板內有{% extends “foo.html” %} 指令將不能訪問comments 模板標籤和過濾器. 子模板必須自己負責{% load comments %} 才可以使用這個庫.

這是為了模板邏輯的清晰性和可維護性有意而為的一個特性.

內建標籤和過濾器參考

下面的標籤和過濾器參考就是為那些沒有admin 站點的可用的人準備的.由於Django 是高度可定制的,你的admin 裡的關於標籤和過濾器的參考可以認為是最可信的.

內建標籤參考

block

定義一個能被子模板覆蓋的塊. 參閱模板繼承了解更多信息

comment

註釋.模板引擎會忽略掉{% comment %} 和{% endcomment %} 之間的所有內容.

cycle

在循環時輪流使用給定的字符串列表中的值.

在一個循環中, 在循環過程中的每次循環裡輪流使用給定的字符串列表元素:

{% for o in some_list %}
    < tr  class = "{% cycle row1,row2 %}" > 
        ...
    < / tr > 
{% endfor %}

在循環之外, 在你第一次調用它時給這些字符串值定義一個不重複的名字,然後在循環中使用這個名字:

<tr class="{% cycle row1,row2,row3 as rowcolors %}">...</tr> <tr class="{% cycle rowcolors %}">...</tr> <tr class= "{% cycle rowcolors %}">...</tr>

你可以使用任意數量的逗號分隔的值.只有一點請你注意,不要在值與值之間放任何空隔–僅僅只有一個逗號即可.

debug

輸出完整的調試信息,包括當前的上下文及導入的模塊信息.

extends

當前模板擴展父模板的一個信號(標記).

這個標籤有兩種使用方式: {% extends “base.html” %} (帶雙引號) 使用“base” 作為要擴展的父模板的名字.或者{% extends variable %} 使用variable 的值作為要擴展的父模板的名字.

參閱模板繼承以了解更多信息.

filter

用來過濾變量的值.

允許多級過濾, 並且他們可以帶有參數運行— just like in variable syntax.

示例:

{% filter escape|lower %}

  文本將被HTML-轉義, 並且全部轉化為小寫

{% end過濾器%}

firstof

輸出傳遞給它的第一個不是False 的變量值. 如果所有的變量都是False 那就不輸出任何東西.

示例:

{% firstof var1 var2 var3 %}

它等價於:

{% if var1 %} {{ var1 }} {% else %}{% if var2 %} {{ var2 }} {% else %}{% if var3 %} {{ var3 }} {% endif %}{% endif %}{% endif %}

for

循環.比如要顯示一個 athlete_list 中的全部運動員:

<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>

通過使用 {% for obj in list reversed %} 你也可以實現反序循環.

在循環過程中for 循環會設置以下的一系列變量:

VariableDescription
forloop.counter當前循環次數(1-indexed)
forloop.counter0當前循環次數(0-indexed)
forloop.revcounter倒序循環時當前循環次數(1-indexed)
forloop.revcounter0倒序循環時當前循環次數(0-indexed)
forloop.first如果當前循環是循環過程的第一次則為True
forloop.last如果當前循環是循環過程的最後一次則為True
forloop.parentloop對嵌套循環, 當前循環之上的循環

if

{% if %} 標籤對一個變量求值,若這個變量為"true" ,就輸出 if 內容塊:

{% if athlete_list %} Number of athletes: {{ athlete_list|length }} 
{% else %} No athletes. 
{% endif %}

在上例中,如果 athlete_list 非空,運動員人數就會通過 {{ athlete_list|length }} 變量顯示出來.

就像你剛剛看到的, if 標籤可以帶一個 {% else %} 子句,用來當 if 測試失敗後輸出相應的內容塊.

if``標籤可以使用 ``and ,“or“或 not 來測試一系列變量或否定一個給定的變量:

{% if athlete_list and coach_list %} Both athletes and coaches are available. {% endif %} {% if not athlete_list %} There are no athletes. {% endif %} {% if athlete_list or coach_list %} There are some athletes or some coaches. {% endif %} {% if not athlete_list or coach_list %} There are no athletes or there are some coaches (OK, so writing English translations of boolean logic sounds stupid; it's not our fault). {% endif %} {% if athlete_list and not coach_list %} There are some athletes and absolutely no coaches. {% endif %}

為避免造成歧義, if``標籤不允許在一個 tag 中同時有 ``and 和 or 邏輯;舉個例子,下面這個語句不能工作:

{% if athlete_list and coach_list or other_list %}

如果確實需要組合條件,可以使用嵌套的 if 實現相同的功能:

{% if athlete_list %} {% if coach_list or other_list %} We have athletes and , either coaches or others. {% endif %} {% endif %}

ifchanged

檢查一個變量自上次循環之後是否發生了改變.(我的理解:主要用於過濾掉重複的值)

'ifchanged' block標籤用於循環中. 它根據自身上次的狀態檢查自己值, 只有值發生變化時才顯示這個值:

<h1>Archive for {{ year }}</h1> {% for day in days %} {% ifchanged %}<h3>{{ day|date:"F" }}</h3>{% endifchanged %} <a href="{{ day|date:"M/d"|lower }}/">{{ day|date:"j" }}</a> {% endfor %}

ifequal

若兩個參數相等,輸出一個內容塊.

例子:

{% ifequal user.id comment.user_id %} ... {% endifequal %}

如同 {% if %} tag,它也支持一個可選的 {% else %} 子句.

參數可以是變量,也可以是字符串字面值, 也就是說下面這樣也是合法的:

{% ifequal user.username "adrian" %} ... {% endifequal %}

ifnotequal

類似 ifequal ,只是它用來測試兩個參數是否不等.

include

載入一個模板並根據當前上下文渲染它.用於在一個模板中包含其它模板.

模板名字可以是一個變量,也可以是一個字符串(帶引號的字符串,無所謂單引號還是雙引號).

下面這個例子包含了 "foo/bar.html" 模板的內容:

{% include "foo/bar.html" %}

下面這個例子包含了另一個模板(該模板的名字為變量 template_name 的值)的內容:

{% include template_name %}

被包含的模板使用包含它的模板的上下文(也就是環境)進行渲染(求值),下面這個例子輸出"Hello, John" :

  • Context: variable person is set to "john" .

  • Template:

    {% include "name_snippet.html" %}
    
  • The name_snippet.html template:

    Hello, {{ person }}
    

參閱: {% ssi %} .

load

裝入一個自定義模板標籤集.

參閱 自定義標籤及過濾器庫 以了解更多信息.

now

顯示當前日期, 根據給定的字符串決定輸出格式.

使用和PHP的 date() 函數一樣的格式碼( http://php.net/date )並做了一些擴展

可用的格式字符串:

格式字符描述輸出示例
a'am' 或 'pm' (注意,它與PHP的輸出略有不同.它包括了句點(django擴展).'am'
A'AM' 或 'PM' .'AM'
B未實現. 
d每月第幾天, 帶前導零'01' to '31'
D每週第幾天,3字母的字符串.'Fri'
f時間, 12-小時制的小時和分鐘數, 如果分鐘數為零,則不顯示.(django 擴展).'1' , '1:30'
F月份, 長文本格式.'January'
g小時, 12-小時制,沒有前導零'1' to '12'
G小時, 24-小時制,沒有前導零'0' to '23'
h小時, 12-小時制,有前導零'01' to '12'
H小時, 24-小時制,有前導零'00' to '23'
i分鐘.'00' to '59'
I未實現 
j每月第幾天, 無前導零'1' to '31'
l每週第幾天,長文本格式.'Friday'
L是否閏年.True or False
m數字表示的月份,有前導零.'01' to '12'
M月份,3字母短文本格式.'Jan'
n數字表示的月份,無前導零'1' to '12'
N出版風格的月份縮寫(django 擴展)'Jan.' , 'Feb.' , 'March' , 'May'
O與格林威治的時間差(以小時計)'+0200'
P12小時制的小時分鐘及'am'/'pm' 分鐘數若為零則不顯示. 用字符串表示特殊的時間點, 如'midnight' 和'noon' (django擴展)'1 a.m.' , '1:30 p.m.' , 'midnight' , 'noon''12:30 p.m.'
rRFC 822 格式的日期 .'Thu, 21 Dec 2000 16:01:07 +0200'
s秒數, 帶有前導零的數字表示'00' to '59'
S英語序數後綴,用於一個月的第幾天,2個字符'st' , 'nd' , 'rd' or 'th'
t給定月共有多少天.28 to 31
T本機時區.'EST' , 'MDT'
U未實現 
w一周中的第幾天,沒有前導零的數字'0' (Sunday) to '6' (Saturday)
WISO-8601 一年的第多少星期數, 一周從星期一開始1 , 23
yYear, 2 位數字表示'99'
YYear, 4 位數字表示'1999'
z一年中的第幾天 .0 to 365
Z以秒計的時區偏移量. 這個偏移量對UTC西部時區總是負數,而對UTC東部時區則總是正數-43200 to 43200

例子:

It is {% now "jS FYH:i" %}

注意你可以使用反斜線轉義一個格式字符串中的敏感字符.(如果你想使用其原始值的話).在下面這個例子裡, "f" 被用反斜線轉義, 因為"f"本身是一個用於顯示時間的格式字符. "o" 不需要被轉義,因為它不是一個格式字符.:

It is the {% now "jS o\f F" %}

(顯示"It is the 4th of September" %}

regroup

Regroup a list of alike objects by a common attribute.

要搞懂這個複雜的標籤, 最好還是用一個例子來說明(一幅圖勝過千句話): 有一個people 對象,它是一個Person 對象(擁有first_name, last_name 及gender 屬性)的列表. 你想顯示一個像下面這樣的列表:

  • Male:
    • George Bush
    • Bill Clinton
  • Female:
    • Margaret Thatcher
    • Condoleezza Rice
  • Unknown:
    • Pat Smith

下面的模板代碼片斷可以完成這個看上去複雜的任務:

{% regroup people by gender as grouped %}
< ul > 
{% for group in grouped %}
    < li > {{ group.grouper }}
    < ul > 
 
        {% for item in group.list %}
        < li > {{ item }} < / li > 
        {% endfor %}
    < / ul > 
{% endfor %}
< / ul >

如同你看到的, {% regroup %} 生成一個變量包含一個對象的列表. 列表中的每個對像都擁有grouper 和list 屬性. grouper 裝有分組的條目; list 包含一系列擁有共同grouper 屬性的對象. 在這個例子裡, grouper 可能是Male, Female 和Unknown, 而list 則是屬於這幾種性別的人的列表.