视图组件与路由组件

9个视图子类

两个视图基类(是视图类):APIView,GenericAPIView
    
五个视图扩展类(不是视图类,需要配合使用):CreateModelMixin,ListModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
    
九个视图子类---》是视图类,不需要额外继承GenericAPIView,只需要继承9个中其中某个,就会有某个或某几个接口
from rest_framework.generics import 
            ListAPIView				查询所有
            CreateAPIView			 新增一个
            ListCreateAPIView		  查询所有,新增一个
            
            RetrieveAPIView			 查询一个
            UpdateAPIView			 修改一个
            DestroyAPIView			 删除一个
            	
            RetrieveUpdateAPIView	 查询一个,修改一个
            RetrieveDestroyAPIView	  查询一个,删除一个
            RetrieveUpdateDestroyAPIView	查询一个,修改一个,删除一个

代码展示

路由:
    urlpatterns = [
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookView.as_view()),
]

视图类:
    class BooksView(ListCreateAPIView):  # 查询一个,新增一个
    queryset = Book.objects.all()
    serializer_class = BookSerializer


class BookView(RetrieveUpdateDestroyAPIView):  # 查询一个,修改一个,删除一个
    queryset = Book.objects.all()
    serializer_class = BookSerializer

总结9个视图子类:
    """
    1 ListAPIView,CreateAPIView
    2 ListAPIView+CreateAPIView  =ListCreateAPIView     给BookView用的
    3 RetrieveAPIView,DestroyAPIView,UpdateAPIView
    4 RetrieveDestroyAPIView,RetrieveUpdateAPIView       发现Destroy和Update的组合没有,就是没有提供,猜测,必须先查出来,再修改或删除,所以它没有
    5 RetrieveUpdateDestroyAPIView  
    """    

视图集

通过ModelViewSet编写5个接口

from rest_framework.viewsets import ModelViewSet
如果两个视图类写成一个路由,会有两个get,路由路径也不一样
drf写了一个类,ModelViewsSet,只要继承它,5个接口都有了,但是路由写法变了
  -重点:一旦继承了ModelViewSet,路由写法变了---变成了.as_view({'get': 'list'})
       -路由做映射,意思是如果get请求,访问这个地址,就执行视图类的list方法

路由:
    urlpatterns = [
    path('admin/', admin.site.urls),

    path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'})),

    path('books/<int:pk>/', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]
    
视图:
class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

通过ReadOnlyModelViewSet编写2个只读接口

from rest_framework.viewsets import ReadOnlyModelViewSet

# 路由
urlpatterns = [
    path('books/', views.BookView.as_view({'get': 'list'})),
    path('books/<int:pk>/', views.BookView.as_view({'get': 'retrieve'})),
]

# 视图类
class BookView(ReadOnlyModelViewSet):  # 查询所有,新增一个,只有读的方法,没有写的方法
    queryset = Book.objects.all()
    serializer_class = BookSerializer

ViewSetMixin源码分析

研究ModelViewSet和ReadOnlyModelViewSet为什么路由写法变了?
        modelViewSet=CreateModelMixin+RetrieveModelMixin+UpdateModelMixin+DestroyModelMixin+ListModelMixin+GenericViewSet(没见过)
    GenericViewSet=ViewSetMixin【没见过】+GenericAPIView【见过,两个视图基类的】
    导致路由写法变了的原因-----》ViewSetMixin 类-----》读--->注释中写了,以后配置路由变成了view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
    @classonlymethod
    def as_view(cls, actions=None, **initkwargs):
     # 在ViewSetMixin类中重写了as_view方法,那么我们想执行ViewSetMixin的as_view就要把这个类放在我们类的第一个继承中
        if not actions:
        # 判断如果没有actions值,就主动抛异常报错
            raise TypeError("The `actions` argument must be provided when "
                            "calling `.as_view()` on a ViewSet. For example "
                            "`.as_view({'get': 'list'})`")

        def view(request, *args, **kwargs):
            self.action_map = actions
            for method, action in actions.items():
             # 这句话表示一次性取出actions的键值对,actions就是我们写的键值对形式的路由,{'get': 'list', 'post': 'create'}循环解压赋值
             # 第一次循环:method:get,action:list
             # 第一次循环:method:post,action:create
                handler = getattr(self, action)
             # 用反射的原理获取actions对应的方法名,action第一次是list去视图类中反射list方法,这个时候handler就是list方法
                setattr(self, method, handler)
     			# 这句话反射修改方法名,将method:get请求方法换为handler:list方法名     
            return self.dispatch(request, *args, **kwargs)
       # 在执行dispatch方法,还是APIView的方法执行handler对应的方法名,也就是list方法
        return csrf_exempt(view)
     # 返回的还是去掉csrf的校验装饰器,执行view函数

总结:
    1.只要继承了ViewSetMixin的视图类,路由写法就编程了(重写的as_view)
    2.编程需要传入字典映射方法:{'get': 'list', 'post': 'create'}
       	-只要传入了actions,以后访问get就是访问list,访问post,就是访问create
    3.其他执行跟之前一样
    4.以后视图类类中的方法名,可以任意命名,只要在路由中做好映射即可【重要】

form rest_framework.viwsets包下的类

from rest_framework.viewsets下有这几个类

GenericViewSet:ViewSetMixin+ GenericAPIView  # 继承GenericAPIView想改变路由写法用这个

ModelViewSet:5个视图扩展类+ViewSetMixin+GenericAPIView

ReadOnlyModelViewSet:2个试图扩展类+ViewSetMixin+GenericAPIView   只读的两个

ViewSet:ViewSetMixin+ APIView				# 继承APIView想改变路由写法用这个

ViewSetMixin:魔法,重新了as_view,只要继承他,以后路由写法变成了映射方法
    
    
"""
重点:
	以后,如果继承APIView,但是想变路由写法【视图类中方法名任意命名】,要继承ViewSet
	如果继承GenericAPIView,但是想变路由写法【视图类中方法名任意命名】,要继承GenericViewSet
"""

视图层大总结

1.两个视图基类
	-APIView,GenericAPIView
    
2.5个视图扩展类,不是视图类,必须配合GenericAPIView
	 CreateModelMixin:新增一个
    ListModelMixin:查询多个
    RetrieveModelMixin:查询一个
    UpdateModelMixin:修改一个
    DestroyModelMixin:删除一个
        
3.9个视图子类,是视图类,只需要继承其中某一个即可
        ListAPIView				查询所有
        CreateAPIView			 新增一个
        ListCreateAPIView		  查询所有,新增一个

        RetrieveAPIView			 查询一个
        UpdateAPIView			 修改一个
        DestroyAPIView			 删除一个

        RetrieveUpdateAPIView	 查询一个,修改一个
        RetrieveDestroyAPIView	  查询一个,删除一个
        RetrieveUpdateDestroyAPIView	查询一个,修改一个,删除一个
        
4.视图集
        -ModelViewSet:路由写法变了,只需要写两行,5个接口都有了
        -ReadOnlyModelViewSet:路由写法变了,只需要写两行,2个只读接口都有了
        -ViewSetMixin:不是视图类,魔法,重写了as_view,路由写法变了,变成映射了
  	      				views.BookView.as_view({'get': 'list', 'post': 'create'})
        -ViewSet:ViewSetMixinViewSetMixin
        -GenericViewSet:ViewSetMixin+ GenericAPIView

# 短信接口,视图类叫SendView,方法叫send_sms,路由配置变了
视图层:
class SendView(ViewSet):
    def send_msg(self, request):
        return Response('发送成功')
路由层:
    urlpatterns = [
    path('admin/', admin.site.urls),
    path('send/', views.SendView.as_view({'get': 'send_msg'})),
    ]
# 这里执行的就是ViewSetMixin的as_view,将get方法转为了send_msg方法执行

路由系统

自动生成路由

drf 由于继承ViewSetMinxin类,路由写法就改变了
	-原生+drf,以后的路由写法,可能会有一下情况(三种情况)
    	-path('books/',views.BookView.as_view())
       -path('books',views.BookView.as_view({'get':'list','post':'create'}))
    	-自动生成

drf提供了两个具有类,继承ModelViewSet后,路由可以自动生成
from rest_framework.routers import SimpleRouter,DefaultRouter
from django.urls import path,include
使用步骤:
    第一步:导入路由类
    第二步:实例化得到对象(两个类,一般使用SimpleRouter)
    第三步:注册:router.register('books',views.BookView,'books')
        # 第一个参数是路径,不要带/
        # 第二个参数是视图类
        # 第三个参数是别名,一般跟路径相同
    第四步:在在urlpatterns中注册,两种方式
        -urlpatterns += router.urls
        -include:path('/api/v1/', include(router.urls))  此方式用的多一些

# 底层实现,自动生成路由
    -本质是自动做映射,能够自动生成的前提是,视图类中要有5个方法的某个或者多个
    		-get---》list
          -get---》retrieve
          -put---》update
          -post---》create
          -delete---》destory
        
        -ModelViewSet,ReadOnlyModelViewSet可以自动生成
        -9个视图子类+配合ViewSetMixin   才可以自动生成
        -GenericAPIView+5个视图扩展类+配合ViewSetMixin   才能自动生成

action装饰器

action 写在视图类的方法上,可以自动生成路由

使用步骤:
    -写在视图类方法上
    class SendView(ViewSet):
        # method指定请求方法,可以传多个
        # detail,只能传True或False
        	-False:不带id的路径:send/send_sms/
           -True:带id的路径:send/2/send_sms/
        # url_path,生成send后路径的名字,默认以方法名命名
        # url_name,别名,反向解析使用
        @action(methos=['POST'],detail=False)
        def send_sms(self,request);
        	pass
 
以后看到的drf路由写法:
    后期,都是自动生成,一般不在urlpatterns 加入路由了
 
补充:
    -1 不同请求方法可以使用不同序列化类
    -2 不同action使用不同序列化类
    class SendView(GenericViewSet):
    queryset = None
    serializer_class = '序列化类'

    def get_serializer(self, *args, **kwargs):
        if self.action=='lqz':
            return '某个序列化类'
        else:
            return '另一个序列化列'
    @action(methods=['GET'], detail=True)
    def send_sms(self, request,pk):
        print(pk)
        # 手机号,从哪去,假设get请求,携带了参数
        phone = request.query_params.get('phone')
        print('发送成功,%s' % phone)
        return Response({'code': 100, 'msg': '发送成功'})

    @action(methods=['GET'], detail=True)
    def lqz(self,request):  # get
        # 序列化类
        pass

    @action(methods=['GET'], detail=True)
    def login(self,request):  # get
        # 序列化类
        pass

image

posted @ 2023-02-06 19:40  雪语  阅读(23)  评论(0编辑  收藏  举报