# 第六节:类视图
# 类视图
在写视图的时候,`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