首页 > 其他分享 >drf-ModelViewSet

drf-ModelViewSet

时间:2023-09-05 22:56:55浏览次数:33  
标签:GenericAPIView get self ModelViewSet 视图 class 路由 drf

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
重写perform_create
def perform_create(self, serializer):
    serializer.save()
视图类的对象中的action参数
print(self.action)  
# 视图类的对象中有个action属性--->它是当次请求执行的方法名的字符串

# 通过action可以限制视图类中某个方法使用的序列化类是哪个

作业

1 importlib 的使用
2 详细的画出视图中所有类,及类的继承关系,及类中的属性和方法 及如何使用-->画图

3 action装饰器
	UserView()--->有register和login方法,完成注册和登录

importlib 的使用

`importlib` 是 Python 的一个内置模块,它提供了动态导入和加载模块的功能。它可以在运行时根据字符串来导入模块,而不是在代码中硬编码模块的名称。

以下是一些 `importlib` 模块的常用函数和用法:

1. `import_module`:用于导入模块。

import importlib

# 导入模块
module = importlib.import_module('module_name')

2. `reload`:用于重新加载已导入的模块。

import importlib

# 重新加载模块
importlib.reload(module)

3. `find_loader`:用于查找模块的加载器。

import importlib

# 查找模块的加载器
loader = importlib.find_loader('module_name')

4. `find_spec`:用于查找模块的规范。

import importlib

# 查找模块的规范
spec = importlib.find_spec('module_name')

5. `util` 模块:提供了一些实用函数,如 `util.spec_from_file_location` 用于创建模块规范。

import importlib.util

# 创建模块规范
spec = importlib.util.spec_from_file_location('module_name', '/path/to/module.py')

6. `import_module` 的子模块 `__import__`:用于动态导入模块。

import importlib.__import__

# 动态导入模块
module = importlib.__import__('module_name')

action装饰器--->UserView()--->有register和login方法,完成注册和登录

视图层
class UserView(ModelViewSet):
    queryset = models.UserInfo.objects.all()
    serializer_class = UserSerializer

    # @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": "注册成功"})

    # @action(methods="POST", detail=False)
    def login(self, request):
        user_obj = self.get_queryset().filter(username=request.data.get("username"),
                                              password=request.data.get("password")).first()
        if user_obj:
            return Response({"code": 200, "msg": "登录成功"})
        else:
            return Response({"code": 1000, "msg": "登录失败"})
路由层
urlpatterns = [
    path('register/', views.UserView.as_view({"post": "register"})),
    path('login/', views.UserView.as_view({"post": "login"})),
]

标签:GenericAPIView,get,self,ModelViewSet,视图,class,路由,drf
From: https://www.cnblogs.com/chao0308/p/17681080.html

相关文章

  • 9个视图子类,视图类,视图集,ViewSetMixin, drf之路由
    1.9个视图子类fromrest_framework.genericsimportListAPIView,CreateAPIView,ListCreateAPIViewfromrest_framework.genericsimportRetrieveAPIView,DestroyAPIView,UpdateAPIViewfromrest_framework.genericsimportRetrieveUpdateDestroyAPIView,RetrieveDes......
  • 9个视图子类、视图集、drf之路由
    9个视图子类fromrest_framework.genericsimportListAPIView,CreateAPIView,ListCreateAPIViewfromrest_framework.genericsimportRetrieveAPIView,DestroyAPIView,UpdateAPIViewfromrest_framework.genericsimportRetrieveUpdateDestroyAPIView,RetrieveDestroy......
  • drf-day7
    九个视图子类以后想写5个接口中的某一个或某几个或所有,只需要选择继承不同的类即可,类中只需要配置两个类属性queryset=Publish.objects.all()serializer_class=PublishSerialize使用九个视图子类两个综合类来写五个接口fromrest_framework.genericsimportListCrea......
  • drf之请求,drf 之响应,drf之响应格式,两个视图基类,基于GenericAPIView,5个视图扩展类
    drf之请求1.1之请求Request类#data#query_params#用起来跟之前一样了解: request._request视图类的方法中:self是咱们写的视图类的对象,self.request是新的request,self.request是一个HttpRequest对象,它提供了许多属性和方法来访问和处理请求的信息.1.2......
  • drf-视图组件
    一、视图DjangoRESTframwork提供的视图的主要作用:控制序列化器的执行(检验、保存、转换数据)控制数据库查询的执行RESTframework提供了众多的通用视图基类与扩展类,以简化视图的编写。1. 两个视图基类1.1APIViewfromrest_framework.viewsimportAPIViewAPIView......
  • drf请求和响应、GenericAPIView封装、5个视图扩展类
    一、drf之请求1、drf之请求Request类视图类继承APIView后多了-0去除了csrf认证-1新的request-request.data-request.query_params-request.其他跟之前一样-request._request是老的-2三大认证-3全局异常2、控制前端请求的编码格式fromrest_fra......
  • drf请求
    drf请求之Request类1、新的request视图层的方法中的request都是这个类(fromrest_framework.requestimportRequest)的对象2、使用request.data取请求体中的数据(之前的Json传值request.body)3、使用request.query_params取请求参数中的数据4、其他属性,用起来和之前一样......
  • django+drf开发一些个人的标准化
    最近在改造一下个人的开发风格。特分享一下。子应用我一般放在apps中,每个不同模块的子应用起不同的名字。startapp后自己移动一下,记得修改一下Appconfig中的name即可。子应用中创建services.py或者如有需要可以创建services模块再细分。所有业务放到services中编写。views一律......
  • 同时创建作者和作者详情表,ModelSerializer使用,模块与包的使用,反序列化校验源码分析
    1同时创建作者和作者详情表1.1django项目改名字后顺利运行#1先改文件夹名#2改项目名#3改项目内的文件夹名#4替换掉所有文件中的drf_day04---》drf_day05#5命令行中启动:pythonmanage.pyrunserver#6setting--->django--->指定项目根路径1.1作者......
  • 同时创建一对一表关系字段(作者和作者详情为例)、ModelSerializer使用、模块与包的使用
    同时创建一对一表关系字段(作者和作者详情为例)序列化器#作者表序列化类classAuthorSerializer(serializers.Serializer):name=serializers.CharField(max_length=32)age=serializers.IntegerField()sex=serializers.CharField(max_length=16)addr......