9个视图子类,视图类,视图集,ViewSetMixin, drf之路由
1. 9个视图子类
from rest_framework.generics import ListAPIView, CreateAPIView, ListCreateAPIView
from rest_framework.generics import RetrieveAPIView, DestroyAPIView, UpdateAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView
# 以后想写5个接口中的某一个或某几个或所有,只需要选择继承不同的类即可,类中只需要配置两个类属性
queryset = Publish.objects.all()
serializer_class = PublishSerializer
1.1 视图类
1 . 想写 publish: 查询所有,查询单条,修改一条,新增一条,删除一条的接口⛵
class PublishView(ListCreateAPIView):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
class PublishDetailView(RetrieveUpdateDestroyAPIView):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
2 . 想写 publish: 查询单条,新增一条,的接口--->使用9个视图子类编写💃
class PublishView(CreateAPIView):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
class PublishDetailView(RetrieveAPIView):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
3. 想写 publish: 查询单条,新增一条,的接口--->使用5个视图扩展类+GenericAPIView 🎀
class PublishView(GenericAPIView,CreateModelMixin):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
def post(self,request,*args,**kwargs):
return self.create(request,*args,**kwargs)
class PublishDetailView(GenericAPIView,RetrieveModelMixin):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
def get(self,request,*args,**kwargs):
return self.retrieve(request,*args,**kwargs)
1.2 路由
path('publish/', PublishView.as_view()),
path('publish/<int:pk>', PublishView.as_view()),
2. 视图集
2.1 ModelViewSet
# 1 只要视图类继承了它,路由写法改一下,5个接口都有了
from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
path('publish/', PublishView.as_view({'get':'list','post':'create'})),
path('publish/<int:pk>', PublishView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
2.1.1 ModelViewSet源码分析
# 有查询所有接口
-get--list----》拿到所有数据,序列化--返回
# 新增一条
-post---create---》之前咱们写的新增的代码一样的
# 为什么get 就变成了list
# 为什么post 就变成了create
在Django的ModelViewSet中,get请求会被映射为list方法,而post请求会被映射为create方法。这是因为ModelViewSet是继承自GenericViewSet类,而GenericViewSet类是继承自APIView类。
在APIView类中,根据请求的方法来调用相应的方法。对于get请求,会调用list方法,对于post请求,会调用create方法。这是因为在RESTful API设计中,get方法通常用于获取资源列表,而post方法通常用于创建新的资源。
2.2 ViewSetMixin
# 没见过
# ViewSetMixin 决定了,以后路由写法就变了
-path('publish/', PublishView.as_view({'get':'list','post':'create'}))
-path('publish/', PublishView.as_view({'get':'lqz'}))
# 源码分析
-class GenericViewSet(ViewSetMixin, generics.GenericAPIView):ViewSetMixin必须放前面--》保证执行的as_view是ViewSetMixin的
-请求来了,路由匹配成功---》执行ViewSetMixin的as_view内的view(request)
def view(request, *args, **kwargs):
self = cls(**initkwargs) # 类实例化得到对象--》self是谁的对象?PublishView
self.action_map = actions # {'get':'list','post':'create'}
# method:get
# action: list
for method, action in actions.items():
# 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方法
2.2.1 以后视图类中方法名可以随意命名,只要路由做好映射
继承的类是:只要继承ViewSetMixin ,就能视图类中方法任意命名,路由写法变化
2.3 ReadOnlyModelViewSet
以后写的接口,只想有 获取单条和获取所有,继承它
2.4 视图层中类的总结
# 1 两个视图基类
-APIView和GenericAPIView
-APIView的执行流程:包装了新的 处理了csrfrequeset,执行了3大认证,处理全局异常
-GenericAPIView:要做序列化,要跟数据库打交道,就直接继承它即可
-queryset # -queryset:以后放所有某个表查询出的数据
-serializer_class # 序列化的类
-get_object # -get_object :修改,查询.的单条
-get_queryset
-get_serializer # -get_serializer :序列化类
# 2 5个视图扩展类(不是视图类),是基于GenericAPIView才能用
-快速使用5个接口
-某几个接口:查询单条,新增一条,的接口--->使用5个视图扩展类+GenericAPIView
class PublishView(GenericAPIView,CreateModelMixin)
queryset=Publish.objects.all()
serializer_class=序列化类
def post(self,request)
return self.create(request)
class PublishDetailView(GenericAPIView,RetrieveModelMixin)
queryset=Publish.objects.all()
serializer_class=序列化类
def get(self,request)
return self.retrieve(request)
# 3 9个视图子类(继承GenericAPIView+5个视图扩展类的组合)
ListAPIView, CreateAPIView
ListCreateAPIView
RetrieveAPIView, DestroyAPIView, UpdateAPIView
RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView
# 4 视图集
-ModelViewSet:
-ViewSetMixin+GenericAPIView+5个视图扩展类
-GenericViewSet+5个视图扩展类
-ViewSetMixin源码:路由做映射的配置,以后视图类中方法可以随便命名
-Viewset:ViewSetMixin+APIView---》不需要要序列化,路由写法变了
-GenericViewSet:ViewSetMixin+GenericAPIView--》需要序列化,需要用数据库,路由写法变化
-ReadOnlyModelViewSet:list和retrieve
3. drf之路由
# 之前路由写法:
path('books/', BookView.as_view())
# 以后一旦继承了ViewSetMixin,就变成了path('publish/', PublishView.as_view({'get': 'list', 'post': 'create'}))
# 这样写起来,做映射,可能有些麻烦,于是drf,帮咱们封装了两个路由类---》可以帮助咱们快速生成之前咱们写的映射关系
###### 必须是继承ViewSetMixin+APIView及其子类才能自动生成 SimpleRouter DefaultRouter
## 自动生成路由:自动映射如下:
{'get': 'list', 'post': 'create'}
{'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}
## 其他的-->视图类中有别的方法,我们想做映射,需要使用装饰器
3.0 使用方式
大前提:必须是继承ViewSetMixin+APIView及其子类才能自动生成
使用步骤:
urls.py中
-
1 导入路由类
from rest_framework.routers import SimpleRouter, DefaultRouter
-
2 类实例化得到对象
router = SimpleRouter()
-
3 自动生成路由,调用对象的某个方法,完成跟视图类的对应关系,映射路由
router.register('publish', PublishView, 'publish')
router.register('books', BookView, 'books') # 后期可以注册更多
router.register('user',UserView,'user')
-
4 把自动生成的路由,加到总路由中
urlpatterns = urlpatterns + router.urls # 两个列表直接相加
-
第四步可以这样写
path('api/v1/', include(router.urls)), # http://127.0.0.1:8008/api/v1/user/register/--->post
3.1 SimpleRouter, DefaultRouter
SimpleRouter, DefaultRouter区别
-DefaultRouter生成的路径多一个根路径 api-root
-DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据
以后就用:SimpleRouter就可以
3.2 action装饰器
# 作用:为视图类中的方法做路径的映射
-这些方法排除5个 :create,list,destroy。。。
# 使用方式
@action(methods=['POST'],detail=False)
def register(self, request):
return Response('register')
# 自动生成:
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
3.3 以后继承ModelViewSet也可也能会重写好多方法
#### 重写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)
if self.request.method=='POST':
return WritePublishSerializer
else:
return self.serializer_class
### 重写perform_create
def perform_create(self, serializer):
serializer.save()
### 序列化使用PublishSerializer,反序列化使用 WritePublishSerializer
3.3 视图类的对象中的action参数
print(self.action)
# 视图类的对象中有个action属性---》它是当次请求执行的方法名的字符串
# 通过action可以限制视图类中某个方法使用的序列化类是哪个
可以通过在视图类中重写get_serializer_class方法来限制特定动作方法的序列化类。
例子:
from rest_framework import viewsets
from rest_framework.decorators import action
class MyViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyDefaultSerializer
def get_serializer_class(self):
if self.action == 'my_action':
return MyCustomSerializer
return super().get_serializer_class()
@action(detail=True, methods=['post'])
def my_action(self, request, pk=None):
# 执行自定义操作
pass
MyViewSet视图类中的my_action方法使用了MyCustomSerializer作为序列化类,而其他方法使用了默认的MyDefaultSerializer。这是通过重写get_serializer_class方法来实现的,根据self.action属性的值来选择序列化类。
思维导图and笼统记忆
-
APIView:
这是DRF中最基础的视图类,提供了处理HTTP请求的基本功能。开发者需要继承该类,并在子类中实现相应的HTTP方法(如get()、post()、put()等)来处理请求。 -
GenericAPIView:
这是一个更高级的通用视图类,结合了APIView和mixins模块的功能。GenericAPIView提供了一些通用的方法和属性,例如get_object()、get_queryset()等,用于简化开发过程。 -
ViewSet:
这是DRF中更高级的视图类,结合了GenericAPIView和mixins模块的功能,并提供了更多的功能和灵活性。ViewSet可以处理常见的CRUD操作,包括list()、create()、retrieve()、update()和destroy()等,通过路由器进行注册和映射。 -
ModelViewSet:
这是一个特殊的ViewSet,专门用于处理与数据库模型相关的操作。ModelViewSet结合了GenericAPIView和ModelMixin的功能,提供了一套完整的CRUD操作,包括列表、创建、检索、更新和删除等。