關於方法調用
方法調用要比其他的查詢稍微複雜一點,下面是需要記住的幾點:
1,在方法查詢的時候,如果一個方法觸發了異常,這個異常會傳遞從而導致渲染失
敗,但是如果異常有一個值爲True的silent_variable_failure屬性,這個變量會渲染成空string:
- >>> t = Template("My name is {{ person.first_name }}.")
- >>> class PersonClas3:
- ... def first_name(self):
- ... raise AssertionError, "foo"
- >>> p = PersonClass3()
- >>> t.render(Context({"person": p}))
- Traceback (most recent call last):
- ...
- AssertionError: foo
- >>> class SilentAssetionError(AssertionError):
- ... silent_variable_failure = True
- >>> class PersonClass4:
- ... def first_name(self):
- ... raise SilentAssertionError
- >>> p = PersonClass4()
- >>> t.render(Context({"person": p}))
- "My name is ."
2,方法調用僅僅在它沒有參數時起作用,否則系統將繼續查找下一個類型(列表索引查詢)
3,顯然一些方法有副作用,讓系統訪問它們是很愚蠢的,而且很可能會造成安全性問
題。
例如你有一個BankAccount對象,該對象有一個delete()方法,模板系統不應該允許做下面的事情
I will now delete this valuable data. {{ account.delete }}
爲了防止這種狀況,可以在方法裏設置一個方法屬性alters_data
如果設置了alters_data=True的話模板系統就不會執行這個方法:
- def delete(self):
- # Delete the account
- delete.alters_data = True
不合法的變量怎樣處理
默認情況下如果變量不存在,模板系統會把它渲染成空string,例如:
- >>> from django.template import Template, Context
- >>> t = Template('Your name is {{ name }}.')
- >>> t.render(Context())
- 'Your name is .'
- >>> t.render(Context({'var': 'hello'}))
- 'Your name is .'
- >>> t.render(Context({'NAME': 'hello'}))
- 'Your name is .'
- >>> t.render(Context({'Name': 'hello'}))
- 'Your name is .'
系統會靜悄悄地顯示錯誤的頁面,而不是產生一個異常,因爲這種情況通常是人爲的錯誤。
在現實情形下,一個web站點因爲一個模板代碼語法的錯誤而變得不可用是不可接受的。
我們可以通過設置Django配置更改Django的缺省行爲,第10章擴展模板引擎會我們會討論這個
玩玩Context對象
大多數情況下你初始化Context對象會傳遞一個字典給Context()
一旦你初始化了Context,你可以使用標準Python字典語法增減Context對象的items:
- >>> from django.template import Context
- >>> c = Context({"foo": "bar"})
- >>> c['foo']
- 'bar'
- >>> del c['foo']
- >>> c['foo']
- ''
- >>> c['newvariable'] = 'hello'
- >>> c['newvariable']
- 'hello'
Context對象是一個stack,你可以push()和pop()
如果你pop()的太多的話它將觸發django.template.ContextPopException:
- >>> c = Context()
- >>> c['foo'] = 'first level'
- >>> c.push()
- >>> c['foo'] = 'second level'
- >>> c['foo']
- 'second level'
- >>> c.pop()
- >>> c['foo']
- 'first level'
- >>> c['foo'] = 'overwritten'
- >>> c['foo']
- 'overwritten'
- >>> c.pop()
- Traceback (most recent call last):
- ...
- django.template.ContextPopException
第10章你會看到使用Context作爲stack自定義模板標籤
模板標籤和過濾器基礎
我們已經提到模板系統使用內建的標籤和過濾器
這裏我們看看常見的,附錄6包含了完整的內建標籤和過濾器,你自己熟悉那個列表來了解可以做什麼是個好主意
if/else
{% if %}標籤計算一個變量值,如果是“true”,即它存在、不爲空並且不是false的boolean值
系統則會顯示{% if %}和{% endif %}間的所有內容:
- {% if today_is_weekend %}
- <p>Welcome to the weekend!</p>
- {% else %}
- <p>Get back to work.</p>
- {% endif %}
{% 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.
- {% endif %}
- {% if athlete_list and not coach_list %}
- There are some athletes and absolutely no coaches.
- {% endif %}
{% if %}標籤不允許同一標籤裏同時出現and和or,否則邏輯容易產生歧義,例如下面的標籤是不合法的:
- {% if athlete_list and coach_list or cheerleader_list %}
如果你想結合and和or來做高級邏輯,只需使用嵌套的{% if %}標籤即可:
- {% if athlete_list %}
- {% if coach_list or cheerleader_list %}
- We have athletes, and either coaches or cheerleaders!
- {% endif %}
- {% endif %}
多次使用同一個邏輯符號是合法的:
- {% if athlete_list or coach_list or parent_list or teacher_list %}
沒有{% elif %}標籤,使用嵌套的{% if %}標籤可以做到同樣的事情:
- {% if athlete_list %}
- <p>Here are the athletes: {{ athlete_list }}.</p>
- {% else %}
- <p>No athletes are available.</p>
- {% if coach_list %}
- <p>Here are the coaches: {{ coach_list }}.</p>
- {% endif %}
- {% endif %}
確認使用{% endif %}來關閉{% if %}標籤,否則Django觸發TemplateSyntaxError
for
{% for %}標籤允許你按順序遍歷一個序列中的各個元素
Python的for語句語法爲for X in Y,X是用來遍歷Y的變量
每次循環模板系統都會渲染{% for %}和{% endfor %}之間的所有內容
例如,顯示給定athlete_list變量來顯示athlete列表:
- <ul>
- {% for athlete in athlete_list %}
- <li>{{ athlete.name }}</li>
- {% endfor %}
- </ul>
在標籤裏添加reversed來反序循環列表:
- {% for athlete in athlete_list reversed %}
- ...
- {% endfor %}
- {% for %}標籤可以嵌套:
- {% for country in countries %}
- <h1>{{ country.name }}</h1>
- <ul>
- {% for city in country.city_list %}
- <li>{{ city }}</li>
- {% endfor %}
- </ul>
- {% endfor %}
系統不支持中斷循環,如果你想這樣,你可以改變你想遍歷的變量來使得變量只包含你想遍歷的值
類似的,系統也不支持continue語句,本章後面的“哲學和限制”會解釋設計的原則
{% for %}標籤內置了一個forloop模板變量,這個變量含有一些屬性可以提供給你一些關於循環的信息
1,forloop.counter表示循環的次數,它從1開始計數,第一次循環設爲1,例如:
- {% for item in todo_list %}
- <p>{{ forloop.counter }}: {{ item }}</p>
- {% endfor %}
2,forloop.counter0類似於forloop.counter,但它是從0開始計數,第一次循環設爲0
3,forloop.revcounter表示循環中剩下的items數量,第一次循環時設爲items總數,最後一次設爲1
4,forloop.revcounter0類似於forloop.revcounter,但它是表示的數量少一個,即最後一次循環時設爲0
5,forloop.first當第一次循環時值爲True,在特別情況下很有用:
- {% for object in objects %}
- {% if forloop.first %}<li class="first">{% else %}<li>{% endif %}
- {{ object }}
- </li>
- {% endfor %}
6,forloop.last當最後一次循環時值爲True
- {% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}
7,forloop.parentloop在嵌套循環中表示父循環的forloop:
- {% for country in countries %}
- <table>
- {% for city in country.city_list %}
- <tr>
- <td>Country #{{ forloop.parentloop.counter }} </td>
- <td>City #{{ forloop.counter }}</td>
- <td>{{ city }}</td>
- </tr>
- {% endfor %}
- </table>
- {% endfor %}
富有魔力的forloop變量只能在循環中得到,當模板解析器到達{% endfor %}時forloop就消失了
如果你的模板context已經包含一個叫forloop的變量,Django會用{% for %}標籤替代它
Django會在for標籤的塊中覆蓋你定義的forloop變量的值
在其他非循環的地方,你的forloop變量仍然可用
我們建議模板變量不要使用forloop,如果你需要這樣做來訪問你自定義的forloop,你可以使用forloop.parentloop
ifequal/ifnotequal
Django模板系統並不是一個嚴格意義上的編程語言,所以它並不允許我們執行Python語句
(我們會在‘哲學和限制‘一節詳細討論)。
然而在模板語言裏比較兩個值並且在他們一致的時候顯示一些內容,確實是一個在常見不過的需求了——所以Django提供了ifequal標籤。
{% ifequal %}比較兩個值,如果相等,則顯示{% ifequal %}和{% endifequal %}之間的所有內容:
- {% ifequal user currentuser %}
- <h1>Welcome!</h1>
- {% endifequal %}
參數可以是硬編碼的string,單引號和雙引號均可,下面的代碼是合法的:
- {% ifequal section 'sitenews' %}
- <h1>Site News</h1>
- {% endifequal %}
- {% ifequal section "community" %}
- <h1>Community</h1>
- {% endifequal %}
和{% if %}一樣,{% ifequal %}標籤支持{% else %}
- {% ifequal section 'sitenews' %}
- <h1>Site News</h1>
- {% else %}
- <h1>No News Here</h1>
- {% endifequal %}
其它的模板變量,strings,integers和小數都可以作爲{% ifequal %}的參數:
- {% ifequal variable 1 %}
- {% ifequal variable 1.23 %}
- {% ifequal variable 'foo' %}
- {% ifequal variable "foo" %}
其它的Python類型,如字典、列表或booleans不能硬編碼在{% ifequal %}裏面,下面是不合法的:
- {% ifequal variable True %}
- {% ifequal variable [1, 2, 3,]%}
- {% ifequal variable {'key': 'value'} %
如果你需要測試某個變量是true或false,用{% if %}即可
註釋
和HTML或編程語言如Python一樣,Django模板語言允許註釋{# #},如:
- {# This is a comment #}
模板渲染時註釋不會輸出,一個註釋不能分成多行
下面的模板渲染時會和模板中的內容一樣,註釋標籤不會解析成註釋
This is a {# comment goes here
and spans another line #}
test.
過濾器
本章前面提到,模板過濾器是變量顯示前轉換它們的值的方式,看起來像下面這樣:
- {{ name|lower }}
這將顯示通過lower過濾器過濾後{{ name }}變量的值,它將文本轉換成小寫
使用(|)管道來申請一個過濾器
過濾器可以串成鏈,即一個過濾器的結果可以傳向下一個
下面是escape文本內容然後把換行轉換成p標籤的習慣用法:
- {{ my_text|escape|linebreaks }}
有些過濾器需要參數,需要參數的過濾器的樣子:
- {{ bio|truncatewords:"30" }}
這將顯示bio標量的前30個字,過濾器參數一直使用雙引號
下面是一些最重要的過濾器:
1,addslashed,在任何後斜線,單引號,雙引號前添加一個後斜線
當你把一些文本輸出到一個JavaScript字符串時這會十分有用
2,date,根據一個格式化string參數來格式化date或datetime對象,例如:
- {{ pub_date|date:"F j, Y" }}
格式化string會在附錄6定義
3,escape,避免給定的string裏出現and符,引號,尖括號
當你處理用戶提交的數據和確認合法的XML和XHTML數據時這將很有用
escape將作如下的一些轉換:
- Converts & to &
- Converts < to <
- Converts > to >
- Converts "(雙引號) to "
- Converts '(單引號) to '
4,length,返回值的長度,你可以在一個list或string上做此操作
或者在任何知道怎樣決定自己的長度的Python對象上做此操作(即有一個__len__()方法的對象)
變量
變量的形式:{{ variable }}
使用句點 “.” 可以訪問變量的屬性.
例如{{ section.title }} 會被 section 對象的 title 屬性替換.
如果你用到的變量不存在,模板系統會插入一個值:TEMPLATE_STRING_IF_INVALID ,這個值在settings中定義, 默認是一個空字符串.
過濾器
可以定製變量的顯示格式。
{{ name|lower }}. 這將顯示 {{ name }} 變量通過 lower 過濾後的值. 它將文本轉換爲小寫.
{{ text|escape|linebreaks }} 用於將文本內容轉義然後將換行轉換成 <p> 標籤.
標籤
{% 標籤 %}
有些標籤要求有開始標記和結束標記,例如: {% block title %}My amazing site{% endblock %}
模板繼承
模板繼承允許你建立一個基本的”骨架”模板, 它包含你所有最常用的站點元素 並 定義了一些可以被子模板覆蓋的block.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>{% block title %}久久尋網{% endblock %}</title>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="side">
{% block side %}
<ul>
<li><a href="/index.html">主頁</a></li>
<li><a href="/blog/index.html">博客</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
我們稱它爲 base.html, 定義了一些簡單的 HTML 骨架文檔, 你可以把它用到一些簡單兩列的網頁上. “子” 模板的任務就是用內容填寫這些空白的內容塊.
子模板
如果你在模板中使用了 “{% extends %}“ ,那麼它必須是這個模板中的第一個模板 tag ,否則它就不工作
如果你需要在子模板中引用父模板中的 block 的內容,使用 “{{ block.super }}“ 變量.這在你希望在父模板的內容之後添加一些內容時會很有用.(你不必完全覆蓋父模板的內容.)
自定義標籤及過濾器庫
某些應用提供自定義標籤和過濾器庫. 要在一個模板中訪問它們, 使用 {% load %} 標籤:
{% load comments %} {% comment_form for blogs.entries entry.id with is_public yes %}
{% load %} 標籤可接受空隔分隔的多個庫的名字作爲參數.{% load comments i18n %}
當你載入一個自定義標籤或過濾器庫, 只有當前模板可以使用這些標籤/過濾器 — 繼承鏈中不論是父模板還是子模板都不能使用使用這些標籤和過濾器.
內建標籤參考
block:定義一個能被子模板覆蓋的塊.
註釋.模板引擎會忽略掉 {% comment %} 和 {% endcomment %} 之間的所有內容.
在循環之外, 在你第一次調用它時給這些字符串值定義一個不重複的名字,然後在循環中使用這個名字:
你可以使用任意數量的逗號分隔的值.只有一點請你注意,不要在值與值之間放任何空隔–僅僅只有一個逗號即可.
debug:輸出完整的調試信息,包括當前的上下文及導入的模塊信息.
filter:用來過濾變量的值
{% 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 %}
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
{% if athlete_list %}
Number of athletes: {{ athlete_list|length }}
{% else %}
No athletes.
{% endif %}
ifchanged:檢查一個變量自上次循環之後是否發生了改變
and,“or“ 或 not
{% ifequal user.id comment.user_id %} …{% endifequal %}
ifnotequal:類似 ifequal, 只是它用來測試兩個參數是否不等.
include:載入一個模板並根據當前上下文渲染它.用於在一個模板中包含其它模板.
模板名字可以是一個變量,也可以是一個字符串(帶引號的字符串,無所謂單引號還是雙引號).
{% include “foo/bar.html” %}
{% include template_name %}
now:顯示當前日期, 根據給定的字符串決定輸出格式.使用和 PHP 的 date() 函數一樣的格式碼。
spaceless:將HTML標籤之間的空白格式化爲一個空格. 空白包括空格,換行,製表符.
{% ssi /home/html/ljworld.com/includes/right_generic.html %} 如果提供了可選的 “parsed” 參數, 被包含文件的內容會使用當前的上下文作爲模板代碼進行求值處理:
{% ssi /home/html/ljworld.com/includes/right_generic.html parsed %}
要創建柱形圖的話, 這個標籤計算給定值與最大值的比率再乘以100,四捨五入爲整數,最後輸出這個整數.
<img src=”bar.gif” height=”10″ width=”{% widthratio this_value max_value 100 %}” />