說是完結,馬上又開始寫進階篇了。
本章不會為部落格專案增加新功能,但是也同樣重要,因為我們要學習高逼格的基於類的檢視。
什麼是類檢視
前面章節中寫的所有檢視都是基於函式的,即def
;而類檢視是基於類的,即class
。
有程式設計基礎的同學都知道,類是物件導向技術中非常重要的概念。具有複雜資料、功能的類,可以通過繼承輕而易舉的將自身特性傳遞給另一個類,從而實現程式碼的高效複用。
相比以前的函式檢視,類檢視有以下優勢:
- HTTP方法(
GET
,POST
等)相關的程式碼,可以通過方法而不是條件分支來組織 - 可以通過諸如mixins(多重繼承)之類的物件導向技術將程式碼分解為可重用元件
說的都是什麼意思?通過例子來感受一下。
列表
函式和類
假設我們有一個部落格列表,列表既有GET方法、又有POST方法,那麼用檢視函式看起來像這樣:
views.pydef article_list_example(request): """處理GET請求""" if request.method == 'GET': articles = ArticlePost.objects.all() context = {'articles': articles
} return render(request, 'article/list.html', context)複製程式碼
而在類檢視中,則變為這樣:
views.pyfrom django.views import Viewclass ArticleListView(View): """處理GET請求""" def get(self, request): articles = ArticlePost.objects.all() context = {'articles': articles
} return render(request, 'article/list.html', context)複製程式碼
從本質上講,基於類的檢視允許你使用不同的類例項方法(即上面的def get()
)響應不同的HTTP請求方法,而不需要使用條件分支程式碼。這樣做的好處是把不同的HTTP請求都分離到獨立的函式中,邏輯更加清晰,並且方便複用。
需要注意的是,因為Django的URL解析器希望將請求傳送到函式而不是類,所以類檢視有一個 as_view()
方法,該方法返回一個函式,當請求匹配關聯模式的URL時,則呼叫該函式。
即,檢視函式的url原本寫為:
urls.py...urlpatterns = [ path('...', views.article_list_example, name='...'),]複製程式碼
類檢視的url需改寫為:
urls.py...urlpatterns = [ path('...', views.ArticleListView.as_view(), name='...'),]複製程式碼
通用檢視
像列表這樣的功能在web開發中是很常見的,開發者會一遍又一遍寫幾乎相同的列表邏輯。Django的通用檢視正是為緩解這種痛苦而開發的。它們對常用模式進行抽象,以便你快速編寫公共檢視,而無需編寫太多程式碼。
因此用列表通用檢視改寫如下:
views.pyfrom django.views.generic import ListViewclass ArticleListView(ListView): # 上下文的名稱 context_object_name = 'articles' # 查詢集 queryset = ArticlePost.objects.all() # 模板位置 template_name = 'article/list.html'複製程式碼
列表繼承了父類ListView
,也就獲得了父類中的處理列表的方法,因此你可以看到,我們在自己的類中沒有寫任何處理的邏輯,僅僅是賦值了幾個變數而已。
動態過濾
從資料庫中篩選特定的內容也是常見的需求,類檢視如何實現呢?
你可能想到了,將上面程式碼中改為queryset = ArticlePost.objects.filter()
就可以了。
除此之外,更好的辦法是覆寫get_queryset()
方法:
views.py...class ArticleListView(ListView): context_object_name = 'articles' template_name = 'article/list.html' def get_queryset(self): """ 查詢集 """ queryset = ArticlePost.objects.filter(title='Python') return queryset複製程式碼
例子中只是過濾出標題為“Python”的文章而已,有些大材小用了;但是你可以在get_queryset()
中寫複雜的聯合查詢邏輯,滿足個性化的功能。
新增上下文
在部落格列表的設計時,我們返回給模板的上下文除了articles
以外,還有很多額外的資訊,如order
、search
;在類檢視中同樣可以實現,改寫get_context_data()
方法即可:
views.py...class ArticleListView(ListView): ... def get_context_data(self, **kwargs): # 獲取原有的上下文 context = super().get_context_data(**kwargs) # 增加新上下文 context['order'] = 'total_views' return context複製程式碼
除此之外,ListView
還有些別的方法可以覆寫,深入瞭解可以看這裡:官方文件
混入類
混入類(Mixin)是指具有某些功能、通常不獨立使用、提供給其他類繼承功能的類。嗯,就是“混入”的字面意思。
前面的列表檢視中已經有get_context_data()
方法了。假設需要寫一個功能類似的視訊列表,就可以用Mixin來避免重複程式碼:
views.py...class ContextMixin: def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['order'] = 'total_views' return contextclass ArticleListView(ContextMixin, ListView): ...class VideoListView(ContextMixin, ListView): ...複製程式碼
通過混入,兩個子類都獲得了get_context_data()
方法。
從語法上看,混入是通過多重繼承實現的。有區別的是,Mixin是作為功能新增到子類中的,而不是作為父類。
實際上Django內建了很多通用的Mixin類,實現了大部分常用的功能,點這裡深入瞭解:官方文件
詳情頁
既然列表都有通用檢視,詳情頁當然也有對應的DetailView
。
用類檢視寫一個簡單的詳情頁:
views.pyfrom django.views.generic import DetailViewclass ArticleDetailView(DetailView): queryset = ArticlePost.objects.all() context_object_name = 'article' template_name = 'article/detail.html'複製程式碼
然後配置url:
urls.py...urlpatterns = [ # 詳情類檢視 path('detail-view/<
int:pk>
/', views.ArticleDetailView.as_view(), name='...'),]複製程式碼
注意這裡傳入的引數不是id
而是pk
,這是檢視的要求(也可以傳入slug
)。pk
是資料表的主鍵,在預設情況下其實就是id
。
這就寫好了!
也可以新增任何別的功能,比如統計瀏覽量:
views.py...class ArticleDetailView(DetailView): ... def get_object(self): """ 獲取需要展示的物件 """ # 首先呼叫父類的方法 obj = super(ArticleDetailView, self).get_object() # 瀏覽量 +1 obj.total_views += 1 obj.save(update_fields=['total_views']) return obj複製程式碼
方法get_object()
的作用是獲取需要展示的物件。首先呼叫父類方法,將這個物件賦值給obj
變數,然後再對其進行統計瀏覽量的操作,最後將物件返回。相當於在原有的方法中把自己的邏輯“塞”了進去。
關於DetailView
更多特性看這裡:官方文件
編輯
除了能夠展示資訊,通用檢視還包含CreateView
、UpdateView
、DeleteView
等編輯資料的類。
如果要新建文章,則檢視可以這麼寫:
views.pyfrom django.views.generic.edit import CreateViewclass ArticleCreateView(CreateView): model = ArticlePost fields = '__all__' # 或者只填寫部分欄位,比如: # fields = ['title', 'content'] template_name = 'article/create_by_class_view.html'複製程式碼
建立create_by_class_view.html
檔案(目錄在哪,你應該已經很清楚了),寫入:
create_by_class_view.html<
form method="post">
{% csrf_token %
} {{
form.as_p
}
} <
input type="submit" value="Save">
<
/form>
複製程式碼
最後新增url:
urls.pyurlpatterns = [ path('create-view/', views.ArticleCreateView.as_view(), name='...'),]複製程式碼
雖然外觀簡陋(這不是重點),但現在這個檢視確實已經能夠建立新文章了!
UpdateView
和DeleteView
這裡就不再贅述了,以後用到的地方再進行講解。
想提前瞭解的同學戳這裡:官方文件
總結
有沒有感受到程式碼隔離和繼承的強大?沒有?以後的章節會逐漸使用類編寫檢視,你會慢慢體會的。
類檢視的內容非常豐富,短短一篇文章只能蜻蜓點水而已。讀者在程式設計中遇到困難了,官方文件是你最好的教程。
如果你有耐心從頭到尾閱讀類檢視的官方文件,那當然是最好的了。
- 有疑問請在杜賽的個人網站留言,我會盡快回復。
- 或Email私信我:dusaiphoto@foxmail.com
- 專案完整程式碼:Django_blog_tutorial
轉載請告知作者並註明出處。