談談django裏的Contex和RequestContext---向模板裏添加全局變量

一直很想仔細研究一下,我在django模板裏,能夠直接訪問變量user, request之類的變量,哪裏來的,到底都有哪些?這會兒週五,我有空來仔細看看代碼。html

模擬一下需求django

  咱們作一個在線商城,須要把這些全局變量注入到全部頁面,如用戶的資料:好比用戶的帳號、用戶的姓名等。api

一般的解決辦法app

  在每一個views方法中經過render_to_response方法注入用戶數據的話,這樣就會作很是多的重複工做,就像下面這樣:  ui

def views_meth1(request):
    return render_to_response('template_1.html', {'user': request.user})
 
def views_meth2(request):
    return render_to_response('template_2.html', {'user': request.user})
 
def views_meth3(request):
    return render_to_response('template_3.html', {'user': request.user})
 
# ...剩下的N個方法

在須要傳入的變量比較簡單、數量較少的時候,這個方法是最簡潔明瞭的。可是一旦須要注入的變量增多,或是須要通過一些額外的計算才能生成的時候,這種方法就會顯得很臃腫,擴展性不好。this

如何避免低效的重複自身代碼,顯然,就是將render_to_response進行再次封裝:spa

# in utils.py:
def mp_render(request, template, context={}):
    context['user'] = request.user
 
    return render_to_response(template, context)
 
# in views.py:
from utils import mp_render
 
def views_meth1(request):
    return mp_render(request, 'template_1.html')
 
def views_meth2(request):
    return mp_render(request, 'template_2.html')
 
def views_meth3(request):
    return mp_render(request, 'template_3.html')

很好理解,有新增長的全局變量須要注入的話,只須要修改mp_render方法就好了。code

django自帶的解決辦法: htm

下面說到重點:先來看看django文檔裏面對於render_to_response這個方法的定義吧,在’Required arguments’裏面,有提到這個方法的第三個參數,叫context_instance,對於這個參數的說明以下:對象

The context instance to render the template with. By default, the template will be rendered with a Context instance (filled with values from dictionary). If you need to use context processors, render the template with a RequestContext instance instead. Your code might look something like this:

大意是:「默認的,render_to_response方法的第二個dictionary參數會被填充爲一個Context對象注入進html模板文件裏面。若是你須要使用context processors,那麼須要使用一個RequestContext對象來渲染模板。」

那麼什麼是context processors呢?看完這一段文檔的定義之後,應該一切就很明瞭了。

首先須要明白在django模板系統中,有兩種封裝模板變量的類,一個是django.template.Context,這是最經常使用的,咱們在使用render_to_response方法的時候傳入的第二個dictionary參數,就會被這個Context類封裝一次,而後傳到模板當中;另外一個是django.template.RequestContext,它和Context類相比有兩個不一樣之處。第一個不一樣的是,在生成一個RequestContext變量的時候,須要傳入一個HttpRequest對象做爲它的第一個參數:

c = RequestContext(request, {'foo': 'bar', })

第二個區別是,它會增長一些自動注入模板的變量,這些變量從哪兒來呢?在django的settings.py裏有一部分是配置TEMPLATE_CONTEXT_PROCESSORS的,這個配置中的那一個個的tuple元素實際上是一個個能夠被調用的方法,而這些方法都會接收一個HttpRequest對象做爲參數,而最終return一個dictionary,這個dictionary裏面的元素就會成爲RequestContext中自動注入模板的變量。咱們看看settings.py中TEMPLATE_CONTEXT_PROCESSORS的某一個元素 django.contrib.auth.context_processors.auth 對應的代碼吧:

# in django/contrib/auth/context_processors.py
def auth(request):
    """ ignore doc string """
    def get_user():
        ....
 
    return {
        'user': SimpleLazyObject(get_user),
        'messages': messages.get_messages(request),
        'perms':  lazy(lambda: PermWrapper(get_user()), PermWrapper)(),
    }

能夠看到,auth方法最後返回的一個字典中,包含了三個元素,因此若是在使用render_to_response方法時,傳入了第三個RequestContext參數,那麼在它所渲染的模板中,就能夠獲取到對應的user、messages、perms變量了。

因此最後文藝解決方法是,在每個須要注入全局變量的views方法中,調用render_to_response的時候,都傳入第三個RequestContext對象參數便可:

def views_meth1(request):
    d1 = {'method': 1}
 
    return render_to_response('template_1.html', d1, context_instance=RequestContext(request))
 
def views_meth2(request):
    d2 = {'method': 2}
 
    return render_to_response('template_2.html', d2, context_instance=RequestContext(request))
 
def views_meth3(request):
    d3 = {'method': 3}
 
    return render_to_response('template_2.html', d3, context_instance=RequestContext(request))

這樣須要注入的全局對象,就能夠經過擴展TEMPLATE_CONTEXT_PROCESSORS來實現,靈活性更高,更易擴展。固然,在通常的項目開發中,我的以爲普通方法也足夠用,因此就根據項目來作取捨吧。

 

參考文章:http://www.kuqin.com/system-analysis/20120210/318036.html

相關文章
相關標籤/搜索