說是完結,立刻又開始寫進階篇了。html
本章不會爲博客項目增長新功能,可是也一樣重要,由於咱們要學習高逼格的基於類的視圖。python
前面章節中寫的全部視圖都是基於函數的,即def
;而類視圖是基於類的,即class
。git
有編程基礎的同窗都知道,類是面向對象技術中很是重要的概念。具備複雜數據、功能的類,能夠經過繼承垂手可得的將自身特性傳遞給另外一個類,從而實現代碼的高效複用。github
相比之前的函數視圖,類視圖有如下優點:web
GET
,POST
等)相關的代碼,能夠經過方法而不是條件分支來組織說的都是什麼意思?經過例子來感覺一下。數據庫
假設咱們有一個博客列表,列表既有GET方法、又有POST方法,那麼用視圖函數看起來像這樣:django
views.py def article_list_example(request): """處理GET請求""" if request.method == 'GET': articles = ArticlePost.objects.all() context = {'articles': articles} return render(request, 'article/list.html', context)
而在類視圖中,則變爲這樣:編程
views.py from django.views import View class 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請求都分離到獨立的函數中,邏輯更加清晰,而且方便複用。ide
須要注意的是,由於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.py from django.views.generic import ListView class 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 context class ArticleListView(ContextMixin, ListView): ... class VideoListView(ContextMixin, ListView): ...
經過混入,兩個子類都得到了get_context_data()
方法。
從語法上看,混入是經過多重繼承實現的。有區別的是,Mixin是 做爲功能添加到子類中的,而不是做爲父類。
實際上Django內置了不少通用的Mixin類,實現了大部分經常使用的功能,點這裏深刻了解:官方文檔
既然列表都有通用視圖,詳情頁固然也有對應的DetailView
。
用類視圖寫一個簡單的詳情頁:
views.py from django.views.generic import DetailView class 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.py from django.views.generic.edit import CreateView class 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.py urlpatterns = [ path('create-view/', views.ArticleCreateView.as_view(), name='...'), ]
雖然外觀簡陋(這不是重點),但如今這個視圖確實已經可以建立新文章了!
UpdateView
和DeleteView
這裏就再也不贅述了,之後用到的地方再進行講解。
想提早了解的同窗戳這裏:官方文檔
有沒有感覺到代碼隔離和繼承的強大?沒有?之後的章節會逐漸使用類編寫視圖,你會慢慢體會的。
類視圖的內容很是豐富,短短一篇文章只能走馬觀花而已。讀者在編程中遇到困難了,官方文檔是你最好的教程。
若是你有耐心從頭至尾閱讀類視圖的官方文檔,那固然是最好的了。
轉載請告知做者並註明出處。