python之路--web--2--Django-12-Django模板語言

Django模板語言

關於本文檔php

本文檔介紹了Django模板系統語言的語法. 若是你但願從一個更技術的角度來看它是如何工做的和如何擴展 它,請參閱 The Django template language: For Python programmers .css

Django模板語言設計的初衷是爲了得到效率和易用性之間的平衡. HTML使用者會感受到他設計的很舒服.若是你有使用其餘基於文本的模板語言如 Smarty 或 CheetahTemplate 的使用經驗,你會感受到使用Django模板語言和那些東西沒什麼兩樣.html

哲理數據庫

若是你有編程背景,或者你使用過PHP等嵌入HTML的程序語言,你要牢記, Django的模板系統是否是簡單的把Python嵌入到HTML中. 它的設計是:模板系統旨在展現內容,而不是程序邏輯.django

Django的模板系統提供的標籤,其功能相似於一些編程結構 – if 標籤用於布爾值測試, for 標籤用來作for循環, 等等.但這些都不是簡單的執行相應的Python代碼,模板系統不會執行任意的Python表達式. 一般狀況下, 模板系統僅支持接下來列出的這些標籤和過濾 (僅當須要時你能夠添加 你本身的擴展 到模板語法中).編程

模板

模板是一個簡單的文本文件.它能夠生成任何基於文本的格式(如 HTML,XML,CSV等).api

模板中包含的 變量 被替換爲變量的值, 標籤 被替換爲相應的模板控制邏輯.數組

下面的一小段模板代碼能夠說明一些基本的內容. 文中的每一個元素都將在後面解釋.:瀏覽器

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

哲理安全

爲何要使用基於文本的模板,而不是基於XML語法的(如Zope的TAL)? 咱們但願Django的模板語言不止是 XML/HTML. 在網絡世界,它能夠不止被用在電子郵件,JavaScript和CSV中. 您能夠在任何文本格式中使用它.

哦,還有一件事: 讓人寫XML, 那就是虐待!

變量

變量看起來是這樣的: {{ 變量 }}. 當模板系統遇到一個變量, 他直接被替換爲他的值. 變量名由字母數字和下劃線 ("_")組成. 點字符 (".") 也能夠出如今變量名中,但他有特殊的含義.好比下面的. 更重要的是, 變量名中不能有空格或其餘的標點符號.

使用點 (.) 來訪問變量的屬性.

幕後

從技術上講,當模板系統遇到一個點,它會嘗試下面的動做,順序以下:

  • 字典查詢
  • 屬性查詢
  • 方法調用
  • 列表索引查找

在上面的例子中, {{ section.title }} 將被替換爲這個對象的title屬性值.

若是你使用一個不存在的變量,模板系統會替換它爲settings中的 TEMPLATE_STRING_IF_INVALID 值,在默認狀況下他被指定爲 '' (空字符串).

過濾器(Filters)

經過使用 過濾器 ,您能夠修改變量的顯示.

過濾器用起來像這樣: {{ name|lower }} . 經過過濾器 lower 變量 {{ name }} 變爲了小寫字符. 經過管道符 (|) 間隔變量和過濾器來使用過濾器.

過濾器能夠是 「鏈式的」. 一個過濾器的輸出做爲下一個過濾器的輸入. {{ text|escape|linebreaks }} 是一種經常使用的轉換方式, 在這以後換行符被替換爲了 <p> 標籤.

有些過濾器是帶有參數的. 一個帶參數的過濾器看起來像這樣: {{ bio|truncatewords:30 }}. 他會顯示 bio 變量的前30個字符.

若是過濾器的參數包含空格, 那麼參數必須被引號包起來; 好比, 用逗號和空格來間隔列表內的元素, 你能夠像這樣用{{ list|join:", }}.

Django提供了約30個內置的過濾器. 有關這些過濾器你能夠在 內置過濾器參考 中找到更詳盡的描述. 這兒有一些過濾器的例子,可讓你嚐到一些過濾器的甜頭:

default

若是一個變量是假的或空的,使用默認值. 不然,使用變量的值

例如:

{{ value|default:"nothing" }} 

若是 value 沒有提供或者爲空,那麼他將顯示爲 「nothing」 。

length

返回的值的長度。能夠被用於字符串或者列表;

for example:

{{ value|length }} 

若是 value 爲 ['a', 'b', 'c', 'd'], 那麼他將被顯示爲 4.

striptags

去掉全部 [X]HTML 標籤. 好比:

{{ value|striptags }} 

若是 value 爲 "<b>Joel</b> <button>is</button> <span>slug</span>", 那麼輸出就會是 "Joel is slug".

這些只是幾個例子,請參閱 內置過濾器參考 的完整列表。

您還能夠建立本身的自定義模板過濾器,請參見 Custom template tags and filters.

查看更多

Django的管理界面能夠在一個給定的站點中包含全部的模板標籤和過濾器的完整參考。 請參閱 The Django admin documentation generator.

標籤(Tags)

標籤看起來像這樣: {% tag %}. 標籤要比變量更復雜: 有些標籤會建立一段文本, 有些標籤會控制輸出流的方式好比循環或邏輯條件, 還有些標籤會添加一些擴展內容到模板中, 好比另外的標籤和過濾器.

有些標籤在使用時須要有開始和結束標籤 (像這樣 {% tag %} ... 內容 ... {% endtag %}).

Django內置了大約二十幾個標籤. 你能夠在 內置標籤參考 閱讀有關內置標籤的內容. 爲了讓你嘗試有什麼可用的, 這裏有一些經常使用標籤的例子:

for

循環數組中的每一個元素. 好比, 顯示列表 athlete_list 中每一個元素的 name 屬性:

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

判斷一個變量的布爾值, 若是它爲 「true」 則顯示 if 塊兒內的內容, 不然顯示 else 塊兒內的文字:

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

在上面的例子中, 若是 athlete_list 不是空的, 那麼變量 {{ athlete_list|length }} 就會被顯示出來.

也能夠在 if 標籤裏使用過濾器和各類操做符:

{% if athlete_list|length > 1 %} Team: {% for athlete in athlete_list %} ... {% endfor %} {% else %} Athlete: {{ athlete_list.0.name }} {% endif %} 
block and  extends
請看  模板繼承 (在下面), 一個強大的方法, 在模板上切割下來的」樣板」.

以上的例子只是整個標籤列表的一小部分; 請參看 內置標籤參考 完整閱覽.

您還能夠建立本身的自定義模板標籤, 請參看 Custom template tags and filters.

查看更多

Django的管理界面能夠在一個給定的站點中包含全部的模板標籤和過濾器的完整參考。 請參閱 The Django admin documentation generator.

註釋(Comments)

要註釋掉行的一部分,在模板中使用註釋語法: {# #}.

例如,該模板將呈現爲 'hello':

{# greeting #}hello

註釋能夠包含任何模板代碼, 使其生效或無效. 例如:

{# {% if foo %}bar{% else %} #}

這個語法只能用於單行註釋 (不容許在 {# 和 #} 之間換行). 若是您須要註釋掉多行部分的模板, 參見 comment 標籤.

模板繼承

Django模板中最強大和最複雜的部分就是模板繼承. 模板繼承容許你創建一個基本的」骨架」模板, 它包含了你網站全部常見的元素,並定義了能夠被子模板覆蓋的 塊(blocks) .

這是最簡單的理解模板繼承的一個例子:

<!DOCTYPE html>
<html 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 標籤, 而且使用子模板的內容替換掉這些塊. 根據變量 blog_entries 的值, 輸出可能看起來像這樣:

<!DOCTYPE html>
<html 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 %} 中的內容會被做爲備用的內容.

在你須要時, 能夠有多個層次的繼承關係. 使用模板繼承的一個經常使用方案是像如下的三層繼承.

  • 建立一個 base.html 模板把控你網站的總體風格.
  • 爲網站的每一個子分類建立一個 base_SECTIONNAME.html 模板. 好比, base_news.htmlbase_sports.html. 這些模板都繼承 base.html 模板. 這些模板中包含特定的設計/風格.
  • 爲每一種類型的頁面建立一個模板, 好比 news article 或 blog 內容. 這些模板擴展上一級模板的相應分類.

這種方法最大限度地重用了代碼並能很容易將元素添加到公用的區域, 好比分類導航.

這裏有一些關於模板繼承的提示

  • 若是你在模板中使用 {% extends %}, 他必須位於模板的最開始. 若是在其餘的部分聲明, 則不生效.

  • 在你的基礎模板中使用更多的 {% block %} 是一個好的方法. 請記住, 子模板不須要定義全部父模板中的塊, 因此你能夠在若干的塊中填充默認值, 而後定義以後須要的塊. 有更多的可用塊老是更好的.

  • 若是你發現本身在許多模板中有重複內容的了, 這可能意味着你要移動這些內容到父模板的 {% block %} 中.

  • 若是你須要獲得父模板塊中的內容, 能夠用 {{ block.super }} 變量. 這在你想使用父模板塊中的內容又想在其中追加內容時是很是有用的. 使用 {{ block.super }} 插入的數據不會被自動轉義 (參見 下一節), 由於它已經被轉義了. 若是須要轉義, 能夠在父模板中轉義.

  • 更好的可讀性, 你能夠給 {% endblock %} 標籤訂義一個 名字. 好比:

    {% block content %} ... {% endblock content %} 

    在一個較長的模板中, 這個方法可讓你知道是哪個 {% block %} 標籤訂義結束了.

最後請注意, 你不能在同一模板中定義多個具備相同名稱的塊標籤. 存在這個限制是由於 block 標籤是」雙向」定義的. 也就是說, 它不只指定了子模板要填充哪一個」洞」, 也說明了子模板要引用那些父模板的內容. 因此在有多個同名 block 標籤時, 父模板就不知道到底要引用哪一個塊的內容了.

自動HTML轉義

從模板生成HTML時, 老是有一種風險, 即一個變量將會影響生成的HTML字符. 例如, 考慮這個模板片斷:

Hello, {{ name }}. 

用這種方法顯示用戶的姓名彷佛沒什麼問題, 但考慮一下, 若是用戶輸入下面的文字做爲他的名字, 會發生什麼:

<script>alert('hello')</script> 

當名字爲這個值, 該模板將呈現爲:

Hello, <script>alert('hello')</script> 

...這意味着瀏覽器將彈出一個JavaScript警告框!

一樣的, 若是名字中包含一個 '<' 符號, 像這樣:

.. code-block:: html
<b>username

這將致使呈現出這樣的模板:

Hello, <b>username

...這意味着在此以後的文字將呈現爲粗體!

顯然, 用戶提交的數據是不可靠的且不該被直接插入到您的網頁, 由於惡意用戶可使用這種潛在的漏洞作很差的事情. 這種類型的安全漏洞被稱爲 Cross Site Scripting (跨站腳本) (XSS) 攻擊.

爲了不這個問題, 你有兩種選擇:

  • 一, 確保讓不受信任的變量通過了 escape 過濾器 (下文介紹), 將危險的HTML字符替換爲無害的HTML轉義字符. 這在Django最初時是默認的方案, 它使得 , 開發者, 有責任確保在必要時轉義了變量. 可是人們很容易忽略它.
  • 二, 你能夠用Django的自動HTML轉義. 本節的其他部分介紹了自動轉義如何工做.

在Django中, 默認每一個模板會自動轉義輸出的每個變量標籤. 具體來講, 這五個字符會被轉義:

  • < 被替換爲 &lt;
  • > 被替換爲 &gt;
  • ' (單引號) 被替換爲 &#39;
  • " (雙引號) 被替換爲 &quot;
  • & 被替換爲 &amp;

再次強調, 這種行爲是默認的. 若是你使用的是Django的模板系統, 你是受保護的.

如何關閉它

若是你不但願數據被自動轉義, 你能夠在站點/模板/變量這三個層面關閉它.

爲何你會想要把它關掉? 由於有時候, 你但願把模板變量中包含的數據做爲原始的HTML渲染, 在這種狀況下, 你不但願本身的內容被轉義. 例如, 你可能在你的數據庫的BLOB字段存儲HTML, 並但願直接嵌入到您的模板. 或者你使用Django的模板系統生成不是HTML的文本 – 好比電子郵件正文.

對於單個變量

要爲一個單獨的變量禁用自動轉義, 使用 safe 過濾器:

這個會被自動轉義: {{ data }} 這個不會被自動轉義: {{ data|safe }} 

safe 能夠被認爲是 safe from further escaping 或 can be safely interpreted as HTML 的簡寫. 在這個例子中, 若是 data 是 '<b>', 那麼輸出將會是:

這個會被自動轉義: &lt;b&gt; 這個不會被自動轉義: <b> 

對於模板文本塊

要在模板中控制自動轉義, 能夠在整個模板 (或者模板的特定區域) 使用 autoescape 標籤, 如:

{% autoescape off %} Hello {{ name }} {% endautoescape %} 

autoescape 標籤接受 on 或 off 做爲參數. 有時, 你但願自動轉義在某個區域被禁用. 如這個模板的例子:

自動轉義是默認被開啓的. 你好 {{ name }} {% autoescape off %} 這個不會被自動轉義: {{ data }}. 這個也不會: {{ other_data }} {% autoescape on %} 自動轉義被開啓: {{ name }} {% endautoescape %} {% endautoescape %} 

自動轉義標籤的效果會傳遞至繼承它的模板中, 包括使用 include 標籤所包含的內容, 就像全部的塊標籤同樣. 例如:

# base.html

{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}


# child.html

{% extends "base.html" %}
{% block title %}This & that{% endblock %}
{% block content %}{{ greeting }}{% endblock %}

因爲自動轉義在base模板中被關閉了, 因此在子模板中他也是被關閉了的, 致使了在呈現HTML時, greeting 變量被輸出爲 <b>Hello!</b>:

<h1>This & that</h1>
<b>Hello!</b>

注意

通常狀況下, 模板的開發者並不須要對自動轉義太過關注. 這是編寫Python的開發者 (寫視圖和寫自定義模板標籤的人) 須要考慮的事. 因此, 你只須要作和模板有關的活.

若是你不肯定模板在什麼時候會進行自動轉義(或不進行), 那麼就向全部須要轉義的變量添加 escape 過濾器. 當自動轉義被打開, 這麼作不會有任何問題, escape 過濾器不會再次轉義 – escape 過濾器不會影響自動轉義的變量.

字符串和自動轉義

正如咱們前面提到的, 過濾器參數能夠是字符串:

{{ data|default:"This is a string literal." }} 

這些做爲過濾器參數的字符串 都不通過 自動轉義, 他們是被認爲通過了 safe 過濾器的. 這麼作的緣由是, 模板的開發者是在控制字符的輸出, 因此他們能確保正確的使用轉義後的HTML字面值.

這意味着你應當這麼寫

{{ data|default:"3 &lt; 2" }} 

...而不是這樣

{{ data|default:"3 < 2" }}  <-- Bad! Don't do this.

這不會影響來自變量自己的數據. 若是必要, 變量自己仍會被自動轉義, 由於他們沒法控制的模板做者.

訪問方法調用

大多附加到對象上的方法均可以在模板中被調用. 這意味着模板能夠從視圖中傳遞過來變量中得到對象屬性以外的值. 例如, Django ORM 提供了 「entry_set」 語法 尋找一個外鍵所關聯的對象的集合. 所以, 架設一個叫 「comment」 的模型有外鍵指向了模型 「task」, 你能夠經過給定一個實際的 task , 像這樣循環輸出它全部的 comment:

{% for comment in task.comment_set.all %} {{ comment }} {% endfor %} 

一樣, QuerySets 提供了一個 count() 方法來統計它所包含的對象數目. 所以, 您能夠獲得當前 task 相關的全部 comment 的數目:

{{ task.comment_set.all.count }} 

固然, 你能夠很容易地訪問你本身的模型中明確地定義的方法:

# In model
class Task(models.Model):
    def foo(self):
        return "bar"

# In template
{{ task.foo }} 

因爲Django有意限制了模板中語言邏輯的處理, 因此不能在模板內調用方法時傳遞參數. 數據應當在視圖中計算, 而後再傳遞給模板.

自定義標籤和過濾器庫

某些應用提供了自定義的標籤和過濾器庫. 要在模板中訪問這些, 應使用 load 標籤:

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

在上文中, load 標籤加載了 comments 標籤庫, 而後 comment_form 標籤就能用了. 你能夠在管理員文檔中找到用戶自定義庫的安裝列表.

load 標籤能夠根據名字加載多個標籤庫, 名字間使用空格分隔. 例如:

{% load comments i18n %} 

請參考 Custom template tags and filters 以得到更多的有關自定義標籤的內容.

自定義庫和模板繼承

當你加載一個自定義標籤和過濾器庫, 這些被加載的標籤/過濾器只能在當前模板中使用 – 其餘與此模板有繼承關係的(父/子)模板均不能使用這些標籤/過濾器.

例如, 若是一個模板 foo.html 使用了 {% load comments %}, 一個子模板 (就是使用了 {% extends "foo.html" %}) 是不能訪問 comments 庫中的標籤和過濾器的. 子模板須要具備本身的 {% load comments %}.

這是由於這能使模板更健全且更好維護.

相關文章
相關標籤/搜索