Django筆記 —— 模板高級進階

  最近在學習Django,打算玩玩網頁後臺方面的東西,由於一直很好奇但卻沒怎麼接觸過。Django對我來講是一個全新的內容,思路想來也是全新的,或許並不能寫得很明白,因此你們就湊合着看吧~html

  本篇筆記(其實個人全部筆記都是),並不會過於詳細的講解。所以若是有你們看不明白的地方,歡迎在我正版博客下留言,有時間的時候我很願意來這裏與你們探討問題。(固然,不能是簡簡單單就能夠百度到的問題-.-)django

  我所選用的教材是《The Django Book 2.0》,本節是第九章,模板高級進階。api


  本節書中內容僅是參考,更可能是按照文檔中內容來介紹。緩存

  主要是由於書中版本過期,不少代碼剛好是1.8中更新的內容,所以只得直接看文檔了。安全


 

0. 目錄app

  1. RequestContext函數和context處理器ide

  2. html自動轉義函數

  3. Django如何加載模板學習

    3.1 什麼是Engine測試

    3.2 加載模板的語句

    3.3 模板加載器

 

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))
View Code

  在上述代碼中,咱們是用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',
]

 

2. html自動轉義

  從模板生成html時,總會有一個風險——變量包含了會影響html的字符。

  書中舉了小例子,這裏不加贅述,直接說解決方法:

    1. 確保每一個不被信任的變量都用escape過濾器過濾一遍,把潛在的有害html字符轉換爲無害的。這是初幾年Django的處理策略。

    2. 利用Django的html自動轉義。下面介紹這種方法。

  只要你使用Django模板,那麼變量標籤中的如下五個字符都會被自動轉義:

原字符 轉義結果
< &lt;
> &gt;
' &#39;
" &quot;
& &amp;

  固然,有時候你會本身手動用模板變量寫一段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 &lt; 2" }}
{{ data|default:"3 < 2" }}  <-- Bad! Don't do this.

   存疑:

    1. escape過濾器是什麼?根據文檔中所寫,好像是專指autoescape標籤?

  

3. Django如何加載模板

  3.1 什麼是Engine

    Engine,簡單來講就是關於模板的一份設置,具體定義這裏暫不介紹,你們能夠先去文章開頭所給的文檔中查看,之後有時間會補上。

    平時加載模板,使用的就是Django中默認的一個Engine對象,其內容就是我們在settings.py中那個TEMPLATES參數。所以,你用默認的方式加載模板,也就等同於你用Django中這個默認的Engine對象來加載模板。這個對象是: django.template.engines['django'] 

    而若是你想要實例化另外一個Engine對象,則須要用這個定義: django.template.Engine() 

  3.2 加載模板的語句

    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的異常。

  3.3 模板加載器

    咱們一直說在加載模板,可是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的兩個類、如何寫獨立模型下的模板……

  但因爲暫時還用不到,因此先不寫了,等之後用到再補充。


  至此,「模板高級進階」內容完結,下一篇是——「模型高級進階」。

相關文章
相關標籤/搜索