9个视图子类
CreateAPIView --继承-->CreateModelMixin、GenericAPIView
ListAPIView --继承-->ListModelMixin、GenericAPIView
RetrieveAPIView --继承-->RetrieveModelMixin、GenericAPIView
DestroyAPIView --继承-->DestroyModelMixin、GenericAPIView
UpdateAPIView --继承-->UpdateModelMixin、GenericAPIView
ListCreateAPIView --继承-->ListModelMixin、GenericAPIView、CreateModelMixin
RetrieveUpdateAPIView --继承-->RetrieveModelMixin、GenericAPIView、UpdateModelMixin
RetrieveDestroyAPIView --继承-->RetrievModelMixin、GenericAPIView、DestroyModelMixin
RetrieveUpdateDestroyAPIView --继承-->UpdateModelMixin、GenericAPIView、RetrieveModelMixin、DestroyModelMixin
继承九个视图子类
#1 想写 publish: 查询所有,查询单条,修改一条,新增一条,删除一条的接口
from rest_framework.generics import ListAPIView, CreateAPIView, DestroyAPIView, RetrieveAPIView, UpdateAPIView, \
ListCreateAPIView, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView
class PublishThreeView(ListCreateAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
class PublishDetailThreeView(RetrieveUpdateDestroyAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
#2 想写 publish: 查询单条,新增一条,的接口--->使用9个视图子类编写
class PublishThreeView(CreateAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
class PublishDetailThreeView(RetrieveAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
#3 想写 publish: 查询单条,新增一条,的接口--->使用5个视图扩展类+GenericAPIVie
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import RetrieveModelMixin, CreateModelMixin
class PublishThreeView(GenericAPIView, CreateModelMixin):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
def post(self, request):
publish_obj = self.get_serializer(data=request.data)
if publish_obj.is_valid():
publish_obj.save()
return Response("hhh")
class PublishDetailThreeView(GenericAPIView, RetrieveModelMixin):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
def get(self, request):
publish_obj = self.get_object()
publish = self.get_serializer(publish_obj)
return Response(publish.data)
视图集
ModelViewSet
如果视图类继承了ModelViewSet,只要将路由改一下,5个接口就都有了
from rest_framework.viewsets import ModelViewSet
ModelViewSet --继承--->5个视图扩展类、GenericViewSet
GenericViewSet --继承--->ViewSetMixin、GenericAPIView
视图层
from rest_framework.viewsets import ModelViewSet
class PublishThreeView(ModelViewSet):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializer
路由层
path('booksthree/', views.PublishThreeView.as_view({"get": "list", "post": "create"})),
path('booksthree/<int:pk>', views.PublishThreeView.as_view({"get": "retrieve", "put": "update", 'delete': 'destroy'})),
ModelViewSet源码分析
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass
# 因为它的源码中什么都没有,所以要到它继承的父类GenericViewSet中查找
class GenericViewSet(ViewSetMixin,generics.GenericAPIView):
pass
# 在GenericViewSet的源码中也什么都没有,所以要去GenericViewSet的父类中查看因为GenericAPIView我们之前已经看过了所以只需要看ViewSetMixin就行了
ViewSetMixin源码分析
1、在源码中能够发现我们之所以要修改路由的写法都是因为ViewSetMixin,它也提醒了我们路由的写法 view = MyViewSet.as_view({'get': 'list', 'post': 'create'})要以这种形式
2、在源码中我们也发现了在ViewSetMixin中重写了as_view的方法,才让路由放生了改变,所以也就是为什么上面的GenericViewSet的继承中ViewSetMixin是放在GenericAPIView前面的原因
请求来了,路由匹配成功->执行ViewSetMixin的as_view内的view(request)
def view(request, *args, **kwargs):
self = cls(**initkwargs) # 类实例化得到对象-->self是谁的对象?PublishView(我视图函数中的类)
self.action_map = actions
# actions = {'get':'list','post':'create'}
for method, action in actions.items():
# method:get action: list
# list 方法
handler = getattr(self, action) #PublishView对象中反射list,拿到了
# 反射设置值
# setattr(PublishView视图类的对象,get,list 方法)
# PublishView视图类的对象中就会有一个get方法,就是list
setattr(self, method, handler)
return self.dispatch(request, *args, **kwargs)
# 总结:
-路由中这样配置:PublishView.as_view({'get':'list','post':'create'})
-以后get请求过来,本质执行的就是视图类中的list方法
所以以后只要是继承了ModelViewSet或者ViewSetMixin,我们类中的方法名就可以随意命名,只要路由做好映射关系就行
ReadOnlyModelViewSet
from rest_framework.viewsets import ReadOnlyModelViewSet
如果只想获取单条和获取全部就选择继承这个类
视图层中类的总结
两个视图基类:
-APIView、GenericAPIView
-APIView:包装了全新的request、处理了csrf验证、三大认证、全局异常捕捉
-GenericAPIView:
-两个重要属性:
queryset、serializer_class
-三个重要方法:
get_queryset、get_serializerget_object
五个视图扩展类(不是视图类),基于GenericAPIView才能用:
CreateModelMixin:添加一条
ListModelMixin:查看所有
RetrieveModelMixin:查看单条
DestroyModelMixin:删除一条
UpdateModelMixin:修改一条
9个视图子类(继承GenericAPIView+5个视图扩展类的组合)
CreateAPIView、ListAPIView
ListCreateAPIView
RetrieveAPIView、DestroyAPIView、UpdateAPIView
RetrieveUpdateAPIView、RetrieveDestroyAPIView
RetrieveUpdateDestroyAPIView
视图集:
ModelViewSet:
GenericViewSet+GenericAPIView+5个视图扩展类
GenericViewSet:
ViewSetMixin+GenericAPIView
ViewSetMixin源码:重写了as_view方法,对路由做了映射的配置,以后在视图类中可以随意命名方法名称
ViewSet:不需要序列化的时候使用ViewSet,但是路由写法变了
ViewSetMixin+APIView
GenericViewSet:需要序列化,需要用到数据库,路由改变
ViewSetMixin+GenericAPIView
drf路由
没有继承ModelViewSet或ViewSetMixin的路由写法:
path('books/', BookView.as_view())
继承了ModelViewSet或ViewSetMixin的路由写法:
方式一:
path('publish/', PublishView.as_view({'get': 'list', 'post': 'create'}))
方式二:
drf帮助我们封装了两个路由类,可以帮助咱们快速生成之前咱们写的映射关系
# 必须是继承ViewSetMixin+APIView及其子类才能自动生成
一旦使用了这两个类就会自动生成路由,自动映射成:
{"get":"list","post":"create"}....这种形式
如果自定义方法的话使用,再使用这两个类,就需要使用到装饰器
使用SimpleRouter
####使用步骤
#### 1 导入路由类
from rest_framework.routers import SimpleRouter, DefaultRouter
#### 2 类实例化得到对象
router = SimpleRouter()
#### 3 自动生成路由,调用对象的某个方法,完成跟视图类的对应关系,映射路由
router.register('publish', PublishView, 'publish')
# register中的参数:前缀、视图类、别名
##### 4 把自动生成的路由,加到总路由中
urlpatterns += router.urls # 两个列表直接相加
使用DefaultRouter
####使用步骤
#### 1 导入路由类
from rest_framework.routers import SimpleRouter, DefaultRouter
#### 2 类实例化得到对象
router = DefaultRouter()
#### 3 自动生成路由,调用对象的某个方法,完成跟视图类的对应关系,映射路由
router.register('publish', PublishView, 'publish')
# register中的参数:前缀、视图类、别名
### 4 在urlpatterns中添加,路由
path('api/v1/', include(router.urls)),
# http://127.0.0.1:8008/api/v1/user/register/--->post
SimpleRouter, DefaultRouter
SimpleRouter, DefaultRouter区别
-DefaultRouter生成的路径多一个根路径 api-root
-DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据
以后就用:SimpleRouter就可以
DefaultRouter不常用,知道有这个路由类就行了
action装饰器
# 作用:为视图类中的自定义方法做路径的映射
-这些方法排除5个请求 :create,list,destroy....
使用方式:
@action(methods=["POST"], detail=False)
def register(self, request):
user_obj = self.get_serializer(data=request.data)
user_obj.is_valid(raise_exception=True)
user_obj.save()
return Response({"code": 200, "msg": user_obj.data})
自动生成:
http://127.0.0.1:8008/user/register/---->post--->就会执行register
action参数:
methods请求方式,可以写多个
detail:路径中是否带id号
http://127.0.0.1:8008/user/register/ # detail=False
http://127.0.0.1:8008/user/4/register/ # detail=True
以后继承ModelViewSet也可能会重写好多方法
比如重写list方法:
#### 重写list
class PublishView(ModelViewSet):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
def list(self, request, *args, **kwargs): # 以后可能会重写list,做自己的定制
res=super().list(request, *args, **kwargs)
return Response({'code':100,'msg':'成功','result':res.data})
重写get_serializer_class
def get_serializer_class(self): # 是GenericAPIView类中的方法,返回什么,以后就以哪个序列化类继续操作
print(self.action)# self.action返回的就是反射的方法
if self.request.method=='POST':
return WritePublishSerializer
else:
return self.serializer_class
def perform_create(self, serializer):
serializer.save()
视图类的对象中的action参数
print(self.action)
# 视图类的对象中有个action属性--->它是当次请求执行的方法名的字符串
# 通过action可以限制视图类中某个方法使用的序列化类是哪个