目录
前篇的view视图例子中,我使用的是APIView,但它没有提供有些现成的方法。
一般好的框架,都会提供一些使用频率很高的方法,比如CURD操作,那drf有不有这方面的类的有的,通用视图generics和视图集ViewSets都可以。这篇先讲前者。
本篇例子也是基于《使用drf改写django连接mysql》的项目代码基础上进行修改的。
一、关于通用视图generics
1.1 基于类的视图
drf中视图基本上是基于类的视图,如APIView、通用视图generic、后面的视图庥ViewSets等。
基于类的视图的主要优点之一是它们允许你组合一些可重用的行为。 REST framework通过提供许多预先构建的视图来提供常用的模式来利用这一优点。
1.2 关于通用视图
1.2.1 介绍
REST framework 提供的通用视图允许您快速构建与数据库模型密切映射的API视图。
如果通用视图不适合你的API的需求,你可以选择使用常规 APIView 类,或重用通用视图使用的mixins和基类来组成你自己的一组可重用的通用视图。
此类扩展了REST框架的 APIView 类,为标准list和detail view 添加了通常需要的行为。提供的每个具体通用视图是通过将 GenericAPIView 与一个或多个mixin类组合来构建的。
1.2.2 属性
以下属性控制着基本视图的行为。
- queryset - 用于从视图返回对象的查询结果集。通常,你必须设置此属性或者重写 get_queryset() 方法。如果你重写了一个视图的方法,重要的是你应该调用 get_queryset() 方法而不是直接访问该属性,因为 queryset 将被计算一次,这些结果将为后续请求缓存起来。
- serializer_class - 用于验证和反序列化输入以及用于序列化输出的Serializer类。 通常,你必须设置此属性或者重写get_serializer_class() 方法。
- lookup_field - 用于执行各个model实例的对象查找的model字段。默认为 'pk'。 请注意,在使用超链接API时,如果需要使用自定义的值,你需要确保在API视图和序列化类都设置查找字段。
- lookup_url_kwarg - 应用于对象查找的URL关键字参数。它的 URL conf 应该包括一个与这个值相对应的关键字参数。如果取消设置,默认情况下使用与 lookup_field相同的值。
上面的意思就是queryset和serializer_class两个属性必须有,如果没有就要重写对应的方法。如果没特殊要求一般添加这2个属性即可
1.2.3 方法
此类提供了一些基础方法
...
这里不写了,自己看。
1.2.4 Mixins
Mixin 类提供用于提供基本视图行为的操作。注意mixin类提供动作方法,而不是直接定义处理程序方法,例如 .get() 和 .post(), 这允许更灵活的行为组成。
Mixin 类可以从 rest_framework.mixins导入。
有了这些Minis就可以直接调用现成的方法使用即可,如
ListModelMixin提供提供一个 .list(request, *args, **kwargs) 方法,实现列出结果集。
看名字都能猜个大概了,同理:
名字 提供的方法 作用 ListModelMixin .list(request, *args, **kwargs) 列出结果集 CreateModelMixin .create(request, *args, **kwargs) 创建和保存一个新的model实例 RetrieveModelMixin .retrieve(request, *args, **kwargs 实现返回响应中现有模型的实例 UpdateModelMixin .update(request, *args, **kwargs) 实现更新和保存现有模型实例 DestroyModelMixin .destroy(request, *args, **kwargs) 实现删除现有模型实例 注:上面这些方法实现都已经帮你写好了,直接使用就行了。如果不符合你的要求你可以重写些方法。
具体看官方文档。
1.2.5 具体的通用视图
名字 | 作用 | http方法 |
---|---|---|
CreateAPIView | 用于 仅创建 端点。 | 提供一个 post 方法处理程序。 |
ListAPIView | 用于 只读 端点以表示模型实例集合 。 | 提供一个 get 方法处理程序。 |
RetrieveAPIView | 用于只读 端点以表示单个模型实例。 | 提供一个 get 方法处理程序。 |
DestroyAPIView | 用于只删除端点以表示单个模型实例。 | 提供一个 delete 方法处理程序。 |
UpdateAPIView | 用于只更新端点以表示单个模型实例。 | 提供一个 put和patch方法处理程序。 |
ListCreateAPIView | 用于读写端点以表示模型实例的集合。 | 提供一个 get 和 post 方法的处理程序 |
RetrieveUpdateAPIView | 用于 读取或更新 端点以表示 单个模型实例。 | 提供 get, put 和 patch 方法的处理程序。 |
RetrieveDestroyAPIView | 用于 读取或删除 端点以表示 单个模型实例。 | 提供 get 和 delete 方法的处理程序。 |
RetrieveUpdateDestroyAPIView | 提供 get, put, patch 和 delete方法的处理程序。 |
1.2.6 其它
都看官方文档吧,不想写重复的事
二、 drf通用视图generics基本写法
2.1 通用视图简洁写法
2.1.1 写法
通过上面介绍知道drf通用视图generics的写法,拿我的stu为例子,代码如下:
class StuList(generics.ListCreateAPIView):
queryset = Stu.objects.all()
serializer_class = StudentSerializer
当你配置路由映射时,使用get方法得到的结果集的值,即 Stu.objects.all() 的执行结果。
2.1.2 作用
上面3行代码是什么意思呢?
我使用了ListCreateAPIView视图,它提供了提供一个 get 和 post 方法的处理程序。按住ctrl不放,点一下 .ListCreateAPIView 会进入该类,如下图所示:
上图中有: ListModelMixin、CreateModelMixin和GenericAPIView
ListModelMixin提供list方法、 .create方法,刚好对应着ListCreateAPIView的get和post。
drf框架自动帮我们关联了,当get操作就转给这个类的list方法,当post操作就转给create方法。而且这2个方法已经写好默认了,一般情况下你不用修改,直接使用就行了。
2.2 例子
我们试下基于《使用drf改写django连接mysql》代码基础上进行一下修改。把APIView部分及url.py配置部分去掉,改成:
from django.http import HttpResponse
from rest_framework import generics
from app.models import Stu
from app.serializers import StudentSerializer
# 主页,普通的django代码
def index(request):
return HttpResponse("hello django")
# 使用drf通用视图,queryset和serializer_class属性不能少
class StuList(generics.ListCreateAPIView):
queryset = Stu.objects.all()
serializer_class = StudentSerializer
url.py部分为:
from django.urls import path
from app import views
urlpatterns = [
# 主页url映射
path('', views.index, name="index"),
# 配置通用视图映射
# as_view()意思是把类中的方法变成对应的http方法:get、post、pub、delete等
path('sid/', views.StuList.as_view(), name='stu-list')
]
.as_view作用:
使用视图函数时,django完成URL解析之后,会直接把request对象以及URL解析器捕获的参数(比如re_path中正则表达捕获的位置参数或关键字参数)丢给视图函数,但是在类视图中,这些参数不能直接丢给一个类,所以就有了as_view方法,这个方法只做一件事就是返回一个闭包,这个闭包像视图函数一样接收url解析器传送过来的参数。
运行一下看一下效果:http://127.0.0.1:8000/sid/,如下图所示:
默认列出了全部。
如果我想一开始只列出第1个呢。可以使用 queryset = Stu.objects.filter(sid='001'),效果如下:
注:不能使用 Stu.objects.get(sid='001') 因为返回的并不是有集合,只是一个stu对象,queryset属性规定是一个集合。
三、例子
3.1 需求
上面例子中的get是没有参数的,如果我想像《使用drf改写django连接mysql》中基于学号查学生成绩这么办,那么就要重写list了。
3.2 实现代码
上面的代码改写如下,添加多一个list方法
from django.http import HttpResponse
from rest_framework import generics
from rest_framework.response import Response
from app.models import Stu
from app.serializers import StudentSerializer
# 主页,普通的django代码
def index(request):
return HttpResponse("hello django")
# 使用drf通用视图,queryset和serializer_class属性不能少
class StuList(generics.ListCreateAPIView):
queryset = Stu.objects.all()
serializer_class = StudentSerializer
def list(self, request, stuSid):
# Note the use of `get_queryset()` instead of `self.queryset`
queryset = Stu.objects.get(sid=stuSid)
# 不能使用 添加many参数,(queryset, many=True),否则会变成多个对象或查询集
# 'Stu' object is not iterable
serializer = StudentSerializer(queryset)
return Response(serializer.data)
url.py改写如下:
path('sid/<str:stuSid>', views.StuList.as_view(), name='stu-list')
3.3 运行效果
打开浏览器输入 http://127.0.0.1:8000/sid/011,011是sid为011的意思
注:最后不能添加斜杠,http://127.0.0.1:8000/sid/011/ 的话会报错出现404
为什么会这样,因为它把sid看成了'011/',所以报错,找不到。