Django搭建個人部落格:基於類的檢視

杜賽_dusai發表於2019-01-16

說是完結,馬上又開始寫進階篇了。

本章不會為部落格專案增加新功能,但是也同樣重要,因為我們要學習高逼格的基於的檢視。

什麼是類檢視

前面章節中寫的所有檢視都是基於函式的,即def;而類檢視是基於類的,即class

有程式設計基礎的同學都知道,是物件導向技術中非常重要的概念。具有複雜資料功能的類,可以通過繼承輕而易舉的將自身特性傳遞給另一個類,從而實現程式碼的高效複用。

相比以前的函式檢視,類檢視有以下優勢:

  • HTTP方法(GETPOST等)相關的程式碼,可以通過方法而不是條件分支來組織
  • 可以通過諸如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以外,還有很多額外的資訊,如ordersearch;在類檢視中同樣可以實現,改寫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更多特性看這裡:官方文件

編輯

除了能夠展示資訊,通用檢視還包含CreateViewUpdateViewDeleteView編輯資料的類。

如果要新建文章,則檢視可以這麼寫:

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='...'),]複製程式碼

雖然外觀簡陋(這不是重點),但現在這個檢視確實已經能夠建立新文章了!

UpdateViewDeleteView這裡就不再贅述了,以後用到的地方再進行講解。

想提前瞭解的同學戳這裡:官方文件

總結

有沒有感受到程式碼隔離繼承的強大?沒有?以後的章節會逐漸使用編寫檢視,你會慢慢體會的。

類檢視的內容非常豐富,短短一篇文章只能蜻蜓點水而已。讀者在程式設計中遇到困難了,官方文件是你最好的教程。

如果你有耐心從頭到尾閱讀類檢視的官方文件,那當然是最好的了。


轉載請告知作者並註明出處。

來源:https://juejin.im/post/5c3f305c51882523f026135f#comment

相關文章