drf-day7

发布时间 2023-09-05 16:42:51作者: Py玩家

九个视图子类

以后想写5个接口中的某一个或某几个或所有,只需要选择继承不同的类即可,类中只需要配置两个类属性

queryset = Publish.objects.all()
serializer_class = PublishSerialize

使用九个视图子类两个综合类来写五个接口

from rest_framework.generics import  ListCreateAPIViewfrom rest_framework.generics import RetrieveUpdateDestroyAPIView
class PublishView(ListCreateAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer

class PublishDetailView(RetrieveUpdateDestroyAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer

使用九个视图子类中的五个单独类来写接口

from rest_framework.generics import ListAPIView, CreateAPIView
from rest_framework.generics import RetrieveAPIView, DestroyAPIView, UpdateAPIView
class PublishView(CreateAPIView, ListAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer

class PublishDetailView(RetrieveAPIView,DestroyAPIView, UpdateAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer

使用五个视图扩展类+genricapiview来写五个接口

from rest_framework.generics import GenericAPIView
from rest_framework.mixins import RetrieveModelMixin, CreateModelMixin, DestroyModelMixin, ListModelMixin, \
    UpdateModelMixin

class AuthorView(GenericAPIView, CreateModelMixin, ListModelMixin):
    # parser_classes = [JSONParser]
    # renderer_classes = [JSONRenderer]
    queryset = Author.objects.all()
    serializer_class = AuthorSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class AuthorDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Author.objects.all()
    serializer_class = AuthorSerializer

    def get(self, request, pk):
        return self.retrieve(request, pk)

    def put(self, request, pk):
        return self.update(request, pk)

    def delete(self, request, pk):
        return self.destroy(request, pk)

路由

path('publish/', PublishView.as_view()),
path('publish/<int:pk>', PublishView.as_view()),

视图集

1、ModelViewSet

只要视图类继承了它,路由写法改一下,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、ModelViewSet源码分析

modelviewset继承了五个视图扩展类和genericviewset,然后genericviewset中继承了viewsetmixin类;viewsetmixin类重写两as_view()方法。

3、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方法

以后视图类中方法名可以随意命名,只要路由做好映射

继承的类是:只要继承ViewSetMixin ,就能视图类中方法任意命名,路由写法变化

ReadOnlyModelViewset

 以后写的接口,只想有 获取单条和获取所有,继承它

视图层中类的总结

# 1 两个视图基类
    APIView和GenericAPIView
    APIView的执行流程:包装了新的  处理了csrfrequeset,执行了3大认证,处理全局异常
    GenericAPIView:要做序列化,要跟数据库打交道,就直接继承它即可
        queryset
        serializer_class
        
        get_object
        get_queryset
        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

drf之路由

之前路由的写法

path('books/', BookView.as_view())

继承viewsetmixin后

path('publish/',PublishView.as_view({'get': 'list', 'post': 'create'}))

继承viewsetmixin后,需要做映射,有一些麻烦,于是drf内部封装两个·路由类,可以帮助我们快速生成映射关系

两个路由类:

from rest_framework.routers import SimpleRouter
from rest_framework.routers import DefaultRouter

自动生成路由:自动映射下面五种

{'get': 'list', 'post': 'create'}
{'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}

除了这五种以外,想给其他方法做映射就需要使用装饰器

 

使用方式

前提:必须继承viewsetmixin+apiview及其子类才可以自动生成路由

url.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  # 两个列表直接相加

上述中的第四步还可以这样写

from django.urls import include
path('api/v1/', include(router.urls))

SimpleRouter、DefaultRouter

区别:
1.DefaultRouter生成的路径多一个根路径 api-root
2.DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据
3.以后就用SimpleRouter

action装饰器

作用:为视图类中的方法做路径的映射

排除:create,list,destroy,retrieve,update这五种方法

使用方法:

from rest_framework.decorators import actio
@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  # detail=False
  http://127.0.0.1:8008/user/4/register/ # detail=True  # detail=True
url_path:定义请求的URL的名称,默认是被装饰的方法名称

以后继承ModelViewSet也可也能会重写好多方法

以后可能会重写list,create等方法

class PublishView(ModelViewSet):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer
    def list(self, request, *args, **kwargs):  
        res=super().list(request, *args, **kwargs)
        return Response({'code':100,'msg':'成功','result':res.data})

重写get_serializer_class

是GenericAPIView类中的方法,返回什么,以后就以哪个序列化类继续操作
def get_serializer_class(self): 
    print(self.action)
    if self.request.method=='POST':
        return WritePublishSerializer
    else:
        return self.serializer_class

重写perform_create

def perform_create(self, serializer):
    serializer.save()
根据self.action参数来决定使用哪一个序列化类来保存,排除不需要的保存的数据
不用action也可以,使用request.path,只是比较麻烦

视图类的对象中的action参数

1.视图类对象中的属性,action是本次请求执行的方法的名称
    eg:def register: action就是register
    
2通过action属性可以限制视图类中的某个方法使用哪一个序列化类