{% raw %}
## 簡介
##譯文同時以 GitHub Issue 的形式發布,[點此閱讀](https://github.com/cundi/Web.Development.with.Django.Cookbook/issues?state=open)。
## 版權協議
除注明外,所有文章均采用 [Creative Commons BY-NC-ND 3.0(自由轉載-保持署名-非商用-非衍生)](http://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh) 協議發布。
這意味著你可以在非商業的前提下免費轉載,但同時你必須:
* 保持文章原文,不作修改。
* 明確署名,即至少注明 `作者:cundi` 字樣以及文章的原始鏈接。
如需商業合作,[請直接聯系作者](https://github.com/cundi/Web.Development.with.Django.Cookbook/issues/3)。
如果你認為譯文對你所有幫助,而且希望看到更多,可以考慮[小額捐助](https://github.com/cundi/Web.Development.with.Django.Cookbook/issues/3)。
-------------------------
# Web.Development.with.Django.Cookbook
中文名:《Django網站開發Cookbook》,14年10月份的新書,可不是09年的那個 Django book
原版英文:https://www.packtpub.com/web-development/web-development-django-cookbook
作者:Aidas Bendoraitis
日期: October 2014
特色:Over 70 practical recipes to create multilingual, responsive, and scalable websites with Django
級別:Cookbook
頁數:Paperback 294 pages
**該書的第二版會在2016年二月份上市,具體情況看Packpub出版社的連接:https://www.packtpub.com/web-development/web-development-django-cookbook-second-edition, 既然都出第二版了還是等新版出來再更新吧**
第五章預覽
*********
第五章 定制模板過濾器和標簽
------------------------
本章,我們會學習以下內容:
* 遵循模板過濾器和標簽的約定
* 創建一個模板過濾器顯示已經過去的天數
* 創建一個模板過濾器提取第一個媒體對象
* 創建一個模板過濾器使URL可讀
* 創建一個模板標簽在模板中載入一個QuerySet
* 創建一個模板標簽為模板解析內容
* 創建一個模板標簽修改request查詢參數
## 簡介
眾所周知,Django有一個非常龐大的模板系統,擁有模板繼承,改變具體值的過濾器,以及屬于顯示邏輯的標簽。此外,Django允許你在應用中添加你自己的模板過濾器和標簽。定制過濾器或者標簽應該位于應用中`templatetags`下的標簽庫文件。你的模板庫在任何模板中使用`{% load %}`模板標簽載入。在這一章,我們會創建多個實用的過濾器和對模板編輯帶來更多控制的標簽。
## 遵循模板過濾器和標簽的規定
如果你么有堅持按指南來做,那么定義模板過濾器和標簽會變得極其混亂不堪。模板過濾器和標簽應該盡可能地服務于模板。它們應該同時具有方便性和靈活性。在這個做法中,我們會看到用來增強Django模板系統功能的規定。
### 如何做
擴展Django模板系統時遵循以下規定:
```
1. 當在視圖,上下文處理器,或者模型方法中,頁面更適合邏輯時,不要創建或者使用定制模板過濾器、標簽。你的頁面是上下文指定時,比如一個對象列表或者一個詳細對象視圖,載入視圖中的對象。如果你需要在每一個頁面都顯示某些內容,可以創建一個上下文管理器。當你需要獲取一個沒有關聯到模板上下文的對象的某些特性時,要用模型的定制方法而不是使用模板過濾器。
```
```
2. 使用 _tags后綴命名模板標簽庫。當你的app命名不同于模板標簽庫時,你可以避免模糊的包導入問題。
```
```python
3. 例如,通過使用如下注釋,在最新創建的庫中,從標簽中分離過濾器:
# -*- coding: UTF-8 -*-
from django import template
register = template.Library()
### FILTERS ###
# .. your filters go here ..
### TAGS ###
# .. your tags go here..
```
```python
4. 通過納入以下格式,創建模板標簽也可以被輕松記住:
for [app_name.model_name]:使用該格式以使用指定的模型
using [template_name]:使用該格式將一個模板的模板標簽輸出
limit [count]:使用該格式將結果限制為一個指定的數量
as [context_variable]:使用該結構可以將結構保存到一個在之后多次使用的上下文變量
```
```
5. 要盡量避免在模板標簽中按位置地定義多個值,除非它們都是不解自明的。否則,這會有可能使開發者迷惑。
```
```
6. 盡可能的使用更多的可理解的參數。沒有引號的字符串應該當作需要解析的上下文變量或者可以提醒你關于模板標簽組件的短語。
```
## 參見
*創建一個顯示已經過去天數的模板過濾器*
*創建一個提取第一個媒體對象的模板過濾器*
*創建一個人類可理解的URL的模板過濾器*
*創建一個接納已經存在的模板的模板標簽*
*創建一個載入模板中的Queryset的模板標簽*
*創建一個可以把內容解析為模板的模板標簽*
*創建一個修改request查詢參數的模板標簽*
## 創建一個顯示已經過去天數的模板過濾器
不是所有的人都需要持續追蹤日期,當論及前沿信息的創建和修改時,對于我們多數人來說,讀取時間的差異會更加便利,例如,三天之前發布的博客文章,當日出版的新聞頭條,昨日最后登錄的用戶。此做法中,我們會創建一個稱為`days_since`的模板過濾器,它會轉換到人類可理解的時間差。
## 準備開始
如果完成操作,可以在設置中的`INSTALLED_APPS`下創建`utils`應用。然后,在這個應用中創建命名為`templatetags`Python包(Python包是一個擁有空的`__init__.py`文件)。
## 怎么做
用下面的內容創建一個`utility_tags.py`文件:
```python
#utils/templatetags/utility_tags.py
# -*- coding: UTF-8 -*-
from datetime import datetime
from django import template
from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now as tz_now
register = template.Library()
### FILTERS ###
@register.filter
def days_since(value):
""" 返回天和值之間的天數."""
today = tz_now().date()
if isinstance(value, datetime.datetime):
value = value.date()
diff = today - value
if diff.days > 1:
return _("%s days ago") % diff.days
elif diff.days == 1:
return _("yesterday")
elif diff.days == 0:
return _("today")
else:
# Date is in the future; return formatted date.
return value.strftime("%B %d, %Y")
```
## 工作原理
如果像下邊這樣在模板中使用這個過濾器,它會返回`yesterday`或者`5 days ago`這樣的內容:
```python
“{% load utility_tags %}
{{ object.created|days_since }}
You can apply this filter to the values of the date and datetime types.
```
你可以應用這個過濾器到`date`的值,和`datetime`的類型。
每個標簽庫都有一個注冊器,它是收集過濾器和標簽的地方。Django過濾器使用`register.filter`裝飾器所注冊的函數。默認,模板系統中的過濾器命名為相同名稱的函數,或者其他的可調用對象。如果你想的話,你可以通過傳遞`name`到裝飾器來為過濾器設置不同的名稱:
```python
@register.filter(name="humanized_days_since")
def days_since(value):
...
```
過濾器本身意思是非常顯而易見的。首先,當前日期被讀取。如果給出的過濾器值是`datetime`類型,那么日期就會被提取。然后,計算今天和提取值之間的差異。視天數而定,返回不同的字符串結果。
## 還有更多
過濾器可以很容易地擴展以顯示時間的不同,比如`just now`, `7 minutes ago`,或者`3 hours ago`。只要操作`datetime`值便是,而不是操作`date`值。
## 參閱
*創建一個提取第一個媒體對象的模板過濾器*
*創建一個人類可理解的URL的模板過濾器*
## 創建一個提取第一個媒體對象的模板過濾器
想象一下,你正在開發一個博客概述頁面,對于每篇文章,你想在這個頁面中顯示內容中的圖片,音樂或者視頻。這樣的情況下,你需要從文章的HTML內容中提取`<img>`,`<object>`,和`<embed>`標簽。這個做法中,我們會見到在`get_first_media`中如何使用正則表達式完成目標。
## 準備開始吧
我們從位于設置中的`INSTALLED_APPS`的`utils`應用開始,并將`templatetags`包置于該應用內部。
## 如何做
在`utility_tags.py`文件中,添加以下內容:
```python
#utils/templatetags/utility_tags.py
# -*- coding: UTF-8 -*-
import re
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
### FILTERS ###
media_file_regex = re.compile(r"<object .+?</object>|"
r"<(img|embed) [^>]+>") )
@register.filter
def get_first_media(content):
""" 返回html內容中第一個圖片或者flash文件 """
m = media_file_regex.search(content)
media_tag = ""
if m:
media_tag = m.group()
return mark_safe(media_tag)
```
## 工作原理
當數據中的HTML內容有效時,把下面的代碼寫到模板里,它會從對象的內容字段重新取回`<object>`,`<img>`或者`<embed>`標簽,或者一個因媒體不存在而出現的空字符串:
```python
{% load utility_tags %}
{{ object.content|get_first_media }}
```
首先,我們把編譯過的正則表達式定義為`media_file_regex`,然后,在過濾器中,我們執行正則表達式模式的搜索。默認,結果會把出現的`<`,`>`和`&`轉義為條目`<`,`>`,以及`&`。我們使用`mark_safe`函數把結果標記為安全的HTML,為在模板中不實用轉義顯示做好準備。
## 還有更多
你可以非常容易地擴展這個過濾器,它也可以提取`<iframe>`標簽(最近它們被Vimeo和Youtube用來內嵌視頻)或者HTML5的`<audio>`和`<video>`標簽,可以像這樣修改正則表達式:
```python
media_file_regex = re.compile(r"<iframe .+?</iframe>|"
r"<audio .+?</ audio>|<video .+?</video>|"
r"<object .+?</object>|<(img|embed) [^>]+>") ”
```
## 參閱
創建一個顯示已經過去天數的模板過濾器
創建一個人類可理解的URL的模板過濾器
#目錄預覽
************
##第一章, **從Django1.6開始**
指導你通過必要的基本配置以新建任意Django項目。本章覆蓋內容有,虛擬環境,會話控制,以及項目設置。
##第二章,**數據庫結構**
教會你如何寫可重復使用的代碼片段并用在模型中。當你創建一個新的app時,要做的第一件就是定義模型。你也告知如何使用South遷移管理數據庫表變更。
##第三章,**表單和視圖**
向你演示使用一些模式為數據創建視圖和表單
##第四章,**模板和JavaScript**
向你演示把模板和JavaScript放在一起使用的實際例子。我們把模板和JavaScript放在一起是因為,總是通過渲染模板將內容展現給用戶,在現代的網站中,JavaScript對于更豐富的用戶體驗也是必要的。
##第五章,**自定義模板過濾器和標簽**
本章向你演示如如何創建并使用模板過濾器和標簽,因為,Django的模板系統包含內容極廣,因此可以有更多的東西對不同的應用場景來添加。
##第六章,**模型管理**
本章,將指導你通過使用自定義的功能來擴展默認admin,
##第七章,**Django CMS**
##第八章,**分層結構**
##第九章,**數據的導入和導出**
##第十章,**附加功能**
{% endraw %}