最近在學習Django,打算玩玩網頁後臺方面的東西,由於一直很好奇但卻沒怎麼接觸過。Django對我來講是一個全新的內容,思路想來也是全新的,或許並不能寫得很明白,因此你們就湊合着看吧~html
本篇筆記(其實個人全部筆記都是),並不會過於詳細的講解。所以若是有你們看不明白的地方,歡迎在我正版博客下留言,有時間的時候我很願意來這裏與你們探討問題。(固然,不能是簡簡單單就能夠百度到的問題-.-)django
我所選用的教材是《The Django Book 2.0》,本節是第九章,模板高級進階。api
本節書中內容僅是參考,更可能是按照文檔中內容來介紹。緩存
主要是由於書中版本過期,不少代碼剛好是1.8中更新的內容,所以只得直接看文檔了。安全
0. 目錄app
1. RequestContext函數和context處理器ide
1. RequestContext函數和context處理器
首先,咱們回顧模板的視圖函數如何書寫:
from django.shortcuts import render_to_response def diary(request): return render_to_response('diary.html', {'name': 'qiqi'})
爲了說明方便,咱們同時給出另外一種寫法:
from django.http import HttpResponse from django.template import loader, Context def diary(request): t = loader.get_template('diary.html') c = Context({'name': 'qiqi'}) return HttpResponse(t.render(c))
或許仍是有同窗看不懂,那我就再給出第三種最笨的等價寫法,你們大可略過直接日後看:
from django.http import HttpResponse from django.template import Template, Context def diary(request): tin = open('./templates/diary.html') html = tin.read() tin.close() inf = {'name': 'qiqi'} t = Template(html) c = Context(inf) return HttpResponse(t.render(c))
在上述代碼中,咱們是用Context函數進行渲染的。
而與django.template.Context函數差很少的,還有一個django.template.RequestContext函數,它默認在模板中加了一些變量,好比HttpRequest對象、當前登陸用戶的相關信息……
來看下面這段代碼:
from django.http import HttpResponse from django.template import loader, Context def view_1(request): # ... t = loader.get_template('template1.html') c = Context({ 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'], 'message': 'I am view 1.' }) return HttpResponse(t.render(c)) def view_2(request): # ... t = loader.get_template('template2.html') c = Context({ 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'], 'message': 'I am the second view.' }) return HttpResponse(t.render(c))
其中app、user、ip_address這三個變量,可能須要在不少模板的渲染中重複寫入,很麻煩。而利用RequestContext函數,咱們即可以將之簡化爲這樣:
from django.http import HttpResponse from django.template import loader, RequestContext def custom_proc(request): return { 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'] } def view_1(request): # ... t = loader.get_template('template1.html') c = RequestContext(request, {'message': 'I am view 1.'}, [custom_proc]) return HttpResponse(t.render(c)) def view_2(request): # ... t = loader.get_template('template2.html') c = RequestContext(request, {'message': 'I am the second view.'}, [custom_proc]) return HttpResponse(t.render(c))
其中,咱們寫的函數custom_proc,便稱爲context處理器。用術語來講,咱們利用RequestContext函數和context處理器,簡化了使用模板的代碼。
而在此基礎上使用render_to_response,咱們還能夠將之簡化成:
from django.shortcuts import render_to_response from django.template import RequestContext def custom_proc(request): return { 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'] } def view_1(request): # ... return render_to_response('template1.html', {'message': 'I am view 1.'}, context_instance=RequestContext(request, [custom_proc])) def view_2(request): # ... return render_to_response('template2.html', {'message': 'I am the second view.'}, context_instance=RequestContext(request, [custom_proc]))
此時,仍是有一點美中不足的——渲染語句中,每次都須要手動爲processors賦值。
Django提供了對全局context處理器的支持——可讓你在全局變量中列出一些context處理器,Django在你每次調用RequestContext函數時都會自動加入這些處理器的。這個全局變量在TEMPLATES參數中能夠找到,其默認值是:
# TEMPLATES參數中,'OPTIONS'字典中的,'context_processors'列表 [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ]
這四個值很少說,能夠去查書和手冊。此時,咱們能夠進一步簡化代碼以下:
from django.shortcuts import render_to_response from django.template import RequestContext def view_1(request): # ... return render_to_response('template1.html', {'message': 'I am view 1.'}, context_instance=RequestContext(request)) def view_2(request): # ... return render_to_response('template2.html', {'message': 'I am the second view.'}, context_instance=RequestContext(request))
至於context處理器,則應當寫在單獨的一份代碼中,推薦命名爲context_processors.py。
只要把這份代碼放在Python搜索路徑中,Django就能夠找到。推薦把它放在project或者app的目錄下。
# context_processors.py def custom_proc(request): return { 'app': 'My app', 'user': request.user, 'ip_address': request.META['REMOTE_ADDR'] }
最後,修改全局變量便可:
[ 'context_processors.custom_proc', ]
從模板生成html時,總會有一個風險——變量包含了會影響html的字符。
書中舉了小例子,這裏不加贅述,直接說解決方法:
1. 確保每一個不被信任的變量都用escape過濾器過濾一遍,把潛在的有害html字符轉換爲無害的。這是初幾年Django的處理策略。
2. 利用Django的html自動轉義。下面介紹這種方法。
只要你使用Django模板,那麼變量標籤中的如下五個字符都會被自動轉義:
原字符 | 轉義結果 |
< | < |
> | > |
' | ' |
" | " |
& | & |
固然,有時候你會本身手動用模板變量寫一段html代碼,那這時候你就須要關閉自動轉義了,關閉方法以下:
1. 變量級別,用safe過濾器: This will not be escaped: {{ data|safe }}
2. 模板級別,用autoescape標籤: {% autoescape off %} ... {% endautoescape %}
這個標籤有兩種狀態:off、on。
這個標籤是能夠嵌套的,例如你能夠在一個off的標籤內嵌套on的標籤。
當你使用模板繼承的時候,顯而易見,這個標籤依舊會持續生效的。
3. 站點級別,這個書中只說有方法,卻沒寫,暫時存疑。
注意:
1. 過濾屢次和過濾一次效果徹底同樣。
2. 模板中的字符串常量(例如過濾器中包含的常量)會逃過自動轉義,而變量中的字符串則不會。
{{ data|default:"3 < 2" }} {{ data|default:"3 < 2" }} <-- Bad! Don't do this.
存疑:
1. escape過濾器是什麼?根據文檔中所寫,好像是專指autoescape標籤?
Engine,簡單來講就是關於模板的一份設置,具體定義這裏暫不介紹,你們能夠先去文章開頭所給的文檔中查看,之後有時間會補上。
平時加載模板,使用的就是Django中默認的一個Engine對象,其內容就是我們在settings.py中那個TEMPLATES參數。所以,你用默認的方式加載模板,也就等同於你用Django中這個默認的Engine對象來加載模板。這個對象是: django.template.engines['django']
而若是你想要實例化另外一個Engine對象,則須要用這個定義: django.template.Engine()
Django加載模板的語句有三種:
1. Engine.from_string(template_code)
按照Engine對象的設置,編譯所給代碼生成模板,返回一個Template對象。
# 方法一,使用默認的Engine from django.template import engines template = engines['django'].from_string(template_code) # 方法二,使用一個空的Engine(沒有context_processors之類的東西) from django.template import Engine template = Engine().from_string(template_code)
2. Engine.get_template(template_name)
按照Engine對象的設置,根據所給名稱找到模板,在內部進行編譯,最後返回一個Template對象。
若是模板不存在,則返回一個TemplateDoesNotExist的異常。
3. Engine.select_template(self, template_name_list)
按照Engine對象的設置,根據所給列表中的名稱,順次尋找模板,把找到的第一個一樣處理,返回一個Template對象。
若是全都不存在,則返回一個TemplateDoesNoeExist的異常。
咱們一直說在加載模板,可是TEMPLATES參數中卻並無加載器的設置,此時咱們所用的一直是Django中默認的加載器。
下面,咱們就一一介紹Django中的模板加載器:
1. django.template.loaders.filesystem.Loader(默認)
從文件系統中加載模板。
路徑:TEMPLATE參數中'DIRS'列表。
2. django.template.loaders.app_directories.Loader
從文件系統中加載模板。
路徑:各app,即INSTALLED_APPS參數每一個app目錄下的templates文件夾。
開啓方式:將TEMPLATES參數中'APP_DIRS'設置爲True。
3. django.template.loaders.eggs.Loader
從Python egg中加載模板。
路徑:各app。
開啓方式:寫出相似代碼(未經測試,僅供參考)——
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'OPTIONS': { 'loaders': [ ('django.template.loaders.eggs.Loader'), ], }, }]
4. django.template.loaders.cached.Loader
加載模板時,第一次調用各加載器加載模板並存入緩存,之後則從緩存中直接加載模板。
路徑:取決於調用的各加載器。
注意:實際加載的各模板應該保證其結點(Node)是進程安全(thread-safe)的,詳見文檔。
開啓方式:寫出相似代碼(源自文檔)——
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'OPTIONS': { 'loaders': [ ('django.template.loaders.cached.Loader', [ 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]), ], }, }]
5. django.template.loaders.locmem.Loader
從Python字典中加載模板,經常使用於測試。
存疑:實際效果未測試過,不是很能理解。
開啓方式:寫出相似代碼(源自文檔)——
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'loaders': [ ('django.template.loaders.locmem.Loader', { 'index.html': 'content here', }), ], }, }]
實際上,書和文檔中還提到了如何寫本身的模板、模板中用於debug的兩個類、如何寫獨立模型下的模板……
但因爲暫時還用不到,因此先不寫了,等之後用到再補充。
至此,「模板高級進階」內容完結,下一篇是——「模型高級進階」。