在早期蛋逾,我們認(rèn)識(shí)到在視圖開發(fā)過程中有共同的用法和模式。這時(shí)我們引入基于函數(shù)的通用視圖來抽象這些模式以簡化常見情形的視圖開發(fā)懊悯。
基于函數(shù)視圖的用法有以下三種:
def index(request):
return HttpResponse('hello world!')
def index(request):
result = {'demo':'demo'}
return render(request, 'blog/about.html', result)
def index(request):
result = {'demo':'demo'}
return render_to_response('blog/about.html', result)
基于函數(shù)的視圖的問題在于蜓谋,雖然它們很好地覆蓋了簡單的情形,但是不能擴(kuò)展或自定義它們炭分,即使是一些簡單的配置選項(xiàng)桃焕,這讓它們?cè)诂F(xiàn)實(shí)應(yīng)用中受到很多限制∨趺基于類的通用視圖然后應(yīng)運(yùn)而生观堂,目的與基于函數(shù)的通用視圖一樣,就是為了使得視圖的開發(fā)更加容易呀忧。
下面三個(gè)是最常使用的基于類的通用視圖:
TemplateView师痕,ListView,DetailView
TemplateView
TemplateView
一般只在需要返回模板時(shí)使用而账。
class ProtectView(TemplateView):
template_name = 'polls/name.html'
TemplateView
可以方便的定義要返回的模板但它不能把數(shù)據(jù)庫中的內(nèi)容查詢展示出來胰坟,所以需要使用 DetailView
和 ListView
。
所有基于類的通用視圖中定義的方法需要在類視圖調(diào)用
as_view()
方法后會(huì)被自動(dòng)調(diào)用泞辐,因?yàn)?Django 的URL
解析器將請(qǐng)求和關(guān)聯(lián)的參數(shù)發(fā)送給一個(gè)可調(diào)用的函數(shù)而不是一個(gè)類笔横,所以基于類的視圖有一個(gè)as_view()
類方法用來作為類的可調(diào)用入口。
ListView
ListView
用于獲取存儲(chǔ)在數(shù)據(jù)庫中的某個(gè) Model
的列表咐吼。
class IndexView(ListView):
"""
首頁視圖函數(shù)吹缔,繼承 ListView ,展示從數(shù)據(jù)庫中獲取的文章列表
"""
template_name = "blog/index.html"
context_object_name = "article_list"
model = Article
template_name
屬性指定了需要渲染的模板锯茄,context_object_name
指定了模板中使用的上下文變量厢塘,model
指定了數(shù)據(jù)的來源。它的功能相當(dāng)于取出了 model
中 Article
的所有數(shù)據(jù)肌幽,使用變量 article_list
傳遞給了 blog/index.html
模板晚碾。ListView
中默認(rèn)使用 object_list
作為上下文變量,可以使用 context_object_name
來自定義上下文變量牍颈,一般使用默認(rèn)的對(duì)模板設(shè)計(jì)者不友好迄薄,所以都是自定義上下文變量的。model
屬性指定了要獲取表中的所有數(shù)據(jù)煮岁,它的功能相當(dāng)于 article_list = Article.objects.all()
讥蔽,但是當(dāng)你需要使用過濾條件或者對(duì)數(shù)據(jù)進(jìn)行一定的操作時(shí),則需要重寫 ListView
中獲取數(shù)據(jù)的方法(get_queryset 方法)画机,像下面這樣:
class IndexView(ListView):
"""
首頁視圖函數(shù)冶伞,繼承 ListView ,展示從數(shù)據(jù)庫中獲取的文章列表
"""
template_name = "blog/index.html"
context_object_name = "article_list"
def get_queryset(self):
"""
重寫 get_queryset 方法步氏,取出發(fā)表的文章并轉(zhuǎn)換文章格式
"""
article_list = Article.objects.filter(status='p')
for article in article_list:
article.body = markdown2.markdown(article.body, extras=['fenced-code-blocks'], )
return article_list
def get_context_data(self, **kwargs):
kwargs['category_list'] = Category.objects.all().order_by('name')
return super(IndexView, self).get_context_data(**kwargs)
此次重寫了 get_context_data
方法响禽,這個(gè)方法是用來添加額外的內(nèi)容傳遞到模板文件的上下文對(duì)象(context)中。上面的例子中將 category_list
添加到上下文變量中荚醒,則在模板中可以使用 {{ }} 來展示 category_list
中的內(nèi)容芋类。
ListView
主要用來獲取某個(gè)model
中的所有數(shù)據(jù),通過template_name
屬性來指定需要渲染的模板,通過context_object_name
屬性來指定上下文變量(默認(rèn)為object_list
)界阁,通過重寫get_queryset
方法來對(duì)model
中的數(shù)據(jù)增加其他邏輯,通過重寫get_context_data
方法來為上下文對(duì)象添加額外的對(duì)象侯繁。
DetailView
ListView
用來獲取某個(gè) model
中的所有數(shù)據(jù),而 DetailView
則是獲取每個(gè)數(shù)據(jù)的詳細(xì)信息泡躯,比如 ListView
獲取所有文章列表贮竟,DetailView
用來獲取文章的詳細(xì)信息。
class ArticleDetailView(DetailView):
"""
文章詳情頁
"""
model = Article
template_name = 'blog/detail.html'
context_object_name = "article"
# 在 urlpattern 中定義的
pk_url_kwarg = 'article_id'
def get_object(self, queryset=None):
"""
獲取對(duì)應(yīng)文章的信息
"""
obj = super(ArticleDetailView, self).get_object()
obj.body = markdown2.markdown(obj.body, extras=['fenced-code-blocks'], )
return obj
# 增加 form 到 context
def get_context_data(self, **kwargs):
kwargs['comment_list'] = self.object.blogcomment_set.all() #獲取評(píng)論
return super(ArticleDetailView, self).get_context_data(**kwargs)
pk_url_kwarg
定義用來獲取對(duì)應(yīng)的單條數(shù)據(jù)较剃,需要傳遞主鍵的值咕别。get_object
方法獲取 pk_url_kwarg
中所要查找的對(duì)象,類似于 ListView
中的 get_queryset
方法写穴,get_context_data
方法和 ListView
中的功能相同惰拱。
DetailView
主要用在獲取某個(gè)model
的單個(gè)對(duì)象中,需要在URL
中傳遞一個(gè)主鍵值進(jìn)行查詢。