# 第六節:類視圖
# 類視圖
在寫視圖的時候,`Django`除了使用函數作為視圖,也可以使用類作為視圖。使用類視圖可以使用類的一些特性,比如繼承等。
## View:
**django.views.generic.base.View**是主要的類視圖,所有的類視圖都是繼承自他。如果我們寫自己的類視圖,也可以繼承自他。然后再根據當前請求的`method`,來實現不同的方法。比如這個視圖只能使用`get`的方式來請求,那么就可以在這個類中定義`get(self,request,*args,**kwargs)`方法。以此類推,如果只需要實現`post`方法,那么就只需要在類中實現`post(self,request,*args,**kwargs)`。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.views <span class="hljs-keyword">import</span> View
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookDetailView</span><span class="hljs-params">(View)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self,request,*args,**kwargs)</span>:</span>
<span class="hljs-keyword">return</span> render(request,<span class="hljs-string">'detail.html'</span>)
```
```
類視圖寫完后,還應該在`urls.py`中進行映射,映射的時候就需要調用`View`的類方法`as_view()`來進行轉換。示例代碼如下:
```
<pre class="calibre12">```
urlpatterns = [
path(<span class="hljs-string">"detail/<book_id>/"</span>,views.BookDetailView.as_view(),name=<span class="hljs-string">'detail'</span>)
]
```
```
除了`get`方法,`View`還支持以下方法`['get','post','put','patch','delete','head','options','trace']`。
如果用戶訪問了`View`中沒有定義的方法。比如你的類視圖只支持`get`方法,而出現了`post`方法,那么就會把這個請求轉發給`http_method_not_allowed(request,*args,**kwargs)`。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AddBookView</span><span class="hljs-params">(View)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">post</span><span class="hljs-params">(self,request,*args,**kwargs)</span>:</span>
<span class="hljs-keyword">return</span> HttpResponse(<span class="hljs-string">"書籍添加成功!"</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">http_method_not_allowed</span><span class="hljs-params">(self, request, *args, **kwargs)</span>:</span>
<span class="hljs-keyword">return</span> HttpResponse(<span class="hljs-string">"您當前采用的method是:%s,本視圖只支持使用post請求!"</span> % request.method)
```
```
`urls.py`中的映射如下:
```
<pre class="calibre12">```
path(<span class="hljs-string">"addbook/"</span>,views.AddBookView.as_view(),name=<span class="hljs-string">'add_book'</span>)
```
```
如果你在瀏覽器中訪問`addbook/`,因為瀏覽器訪問采用的是`get`方法,而`addbook`只支持`post`方法,因此以上視圖會返回您當前采用的`method`是:`GET`,本視圖只支持使用`post`請求!。
其實不管是`get`請求還是`post`請求,都會走`dispatch(request,*args,**kwargs)`方法,所以如果實現這個方法,將能夠對所有請求都處理到。
## TemplateView:
**django.views.generic.base.TemplateView**,這個類視圖是專門用來返回模版的。在這個類中,有兩個屬性是經常需要用到的,一個是`template_name`,這個屬性是用來存儲模版的路徑,`TemplateView`會自動的渲染這個變量指向的模版。另外一個是`get_context_data`,這個方法是用來返回上下文數據的,也就是在給模版傳的參數的。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.views.generic.base <span class="hljs-keyword">import</span> TemplateView
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomePageView</span><span class="hljs-params">(TemplateView)</span>:</span>
template_name = <span class="hljs-string">"home.html"</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_context_data</span><span class="hljs-params">(self, **kwargs)</span>:</span>
context = super().get_context_data(**kwargs)
context[<span class="hljs-string">'username'</span>] = <span class="hljs-string">"黃勇"</span>
<span class="hljs-keyword">return</span> context
```
```
在`urls.py`中的映射代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path
<span class="hljs-keyword">from</span> myapp.views <span class="hljs-keyword">import</span> HomePageView
urlpatterns = [
path(<span class="hljs-string">''</span>, HomePageView.as_view(), name=<span class="hljs-string">'home'</span>),
]
```
```
如果在模版中不需要傳遞任何參數,那么可以直接只在`urls.py`中使用`TemplateView`來渲染模版。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.urls <span class="hljs-keyword">import</span> path
<span class="hljs-keyword">from</span> django.views.generic <span class="hljs-keyword">import</span> TemplateView
urlpatterns = [
path(<span class="hljs-string">'about/'</span>, TemplateView.as_view(template_name=<span class="hljs-string">"about.html"</span>)),
]
```
```
## ListView:
在網站開發中,經常會出現需要列出某個表中的一些數據作為列表展示出來。比如文章列表,圖書列表等等。在`Django`中可以使用`ListView`來幫我們快速實現這種需求。示例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArticleListView</span><span class="hljs-params">(ListView)</span>:</span>
model = Article
template_name = <span class="hljs-string">'article_list.html'</span>
paginate_by = <span class="hljs-params">10</span>
context_object_name = <span class="hljs-string">'articles'</span>
ordering = <span class="hljs-string">'create_time'</span>
page_kwarg = <span class="hljs-string">'page'</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_context_data</span><span class="hljs-params">(self, **kwargs)</span>:</span>
context = super(ArticleListView, self).get_context_data(**kwargs)
print(context)
<span class="hljs-keyword">return</span> context
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_queryset</span><span class="hljs-params">(self)</span>:</span>
<span class="hljs-keyword">return</span> Article.objects.filter(id__lte=<span class="hljs-params">89</span>)
```
```
對以上代碼進行解釋:
1. 首先`ArticleListView`是繼承自`ListView`。
2. `model`:重寫`model`類屬性,指定這個列表是給哪個模型的。
3. `template_name`:指定這個列表的模板。
4. `paginate_by`:指定這個列表一頁中展示多少條數據。
5. `context_object_name`:指定這個列表模型在模板中的參數名稱。
6. `ordering`:指定這個列表的排序方式。
7. `page_kwarg`:獲取第幾頁的數據的參數名稱。默認是`page`。
8. `get_context_data`:獲取上下文的數據。
9. `get_queryset`:如果你提取數據的時候,并不是要把所有數據都返回,那么你可以重寫這個方法。將一些不需要展示的數據給過濾掉。
## Paginator和Page類:
`Paginator`和`Page`類都是用來做分頁的。他們在`Django`中的路徑為`django.core.paginator.Paginator`和`django.core.paginator.Page`。以下對這兩個類的常用屬性和方法做解釋:
### Paginator常用屬性和方法:
1. `count`:總共有多少條數據。
2. `num_pages`:總共有多少頁。
3. `page_range`:頁面的區間。比如有三頁,那么就`range(1,4)`。
### Page常用屬性和方法:
1. `has_next`:是否還有下一頁。
2. `has_previous`:是否還有上一頁。
3. `next_page_number`:下一頁的頁碼。
4. `previous_page_number`:上一頁的頁碼。
5. `number`:當前頁。
6. `start_index`:當前這一頁的第一條數據的索引值。
7. `end_index`:當前這一頁的最后一條數據的索引值。
## 給類視圖添加裝飾器:
在開發中,有時候需要給一些視圖添加裝飾器。如果用函數視圖那么非常簡單,只要在函數的上面寫上裝飾器就可以了。但是如果想要給類添加裝飾器,那么可以通過以下兩種方式來實現:
### 裝飾dispatch方法:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.utils.decorators <span class="hljs-keyword">import</span> method_decorator
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">login_required</span><span class="hljs-params">(func)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span><span class="hljs-params">(request,*args,**kwargs)</span>:</span>
<span class="hljs-keyword">if</span> request.GET.get(<span class="hljs-string">"username"</span>):
<span class="hljs-keyword">return</span> func(request,*args,**kwargs)
<span class="hljs-keyword">else</span>:
<span class="hljs-keyword">return</span> redirect(reverse(<span class="hljs-string">'index'</span>))
<span class="hljs-keyword">return</span> wrapper
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexView</span><span class="hljs-params">(View)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self,request,*args,**kwargs)</span>:</span>
<span class="hljs-keyword">return</span> HttpResponse(<span class="hljs-string">"index"</span>)
<span class="hljs-class"> @method_decorator(login_required)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">dispatch</span><span class="hljs-params">(self, request, *args, **kwargs)</span>:</span>
super(IndexView, self).dispatch(request,*args,**kwargs)
```
```
### 直接裝飾在整個類上:
```
<pre class="calibre12">```
<span class="hljs-keyword">from</span> django.utils.decorators <span class="hljs-keyword">import</span> method_decorator
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">login_required</span><span class="hljs-params">(func)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span><span class="hljs-params">(request,*args,**kwargs)</span>:</span>
<span class="hljs-keyword">if</span> request.GET.get(<span class="hljs-string">"username"</span>):
<span class="hljs-keyword">return</span> func(request,*args,**kwargs)
<span class="hljs-keyword">else</span>:
<span class="hljs-keyword">return</span> redirect(reverse(<span class="hljs-string">'login'</span>))
<span class="hljs-keyword">return</span> wrapper
<span class="hljs-class">@method_decorator(login_required,name='dispatch')</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IndexView</span><span class="hljs-params">(View)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span><span class="hljs-params">(self,request,*args,**kwargs)</span>:</span>
<span class="hljs-keyword">return</span> HttpResponse(<span class="hljs-string">"index"</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">dispatch</span><span class="hljs-params">(self, request, *args, **kwargs)</span>:</span>
super(IndexView, self).dispatch(request,*args,**kwargs)
```
```
- Introduction
- 第一章:學前準備
- 第一節:虛擬環境
- 第二節:準備工作
- 第三節:Django介紹
- 第四節:URL組成部分
- 第二章:URL與視圖
- 第一節:第一個Django項目
- 第二節:視圖與URL分發器
- 第三章:模板
- 第一節:模板介紹
- 第二節:模板變量
- 第三節:常用標簽
- 第四節:常用過濾器
- 第五節:自定義過濾器
- 第七節:模版結構優化
- 第八節:加載靜態文件
- 第四章:數據庫
- 第一節:MySQL相關軟件
- 第二節:數據庫操作
- 第三節:ORM模型
- 第四節:模型常用字段
- 第五節:外鍵和表關系
- 第六節:增刪改查操作
- 第七節:查詢操作
- 第八節:QuerySet API
- 第九節:ORM模型遷移
- 第十節:ORM作業
- 第十一節:ORM作業參考答案
- 第十二節:Pycharm連接數據庫
- 第五章:視圖高級
- 第一節:限制請求method
- 第二節:頁面重定向
- 第三節:HttpRequest對象
- 第四節:HttpResponse對象
- 第五節:生成CSV文件
- 第六節:類視圖
- 第七節:錯誤處理
- 第六章:表單
- 第一節:表單概述
- 第二節:用表單驗證數據
- 第三節:ModelForm
- 第四節:文件上傳
- 第七章:cookie和session
- 第八章:上下文處理器和中間件
- 第一節:上下文處理器
- 第二節:中間件
- 第九章:安全
- 第一節:CSRF攻擊
- 第二節:XSS攻擊
- 第三節:點擊劫持攻擊
- 第四節:SQL注入
- 第十章:信號
- 第一節:什么是信號
- 第十一章:驗證和授權
- 第一節:概述
- 第二節:用戶對象
- 第三節:權限和分組
- 第十二章:Admin系統
- 第十三章:Django的緩存
- 第十四章:memcached
- 第十五章:Redis