drf之视图子类、视图集、路由

本文介绍了Django REST Framework(DRF)中的视图子类,包括9个视图子类的功能和应用场景。重点讨论了ModelViewSet、ViewSetMixin以及ReadOnlyModelViewSet,讲解了它们的源码分析、自定义方法和路由配置。同时,文章还涵盖了路由的使用,如SimpleRouter和DefaultRouter,并介绍了action装饰器的用法以及如何重写视图类的方法来定制行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 9个视图子类

9个视图子类就是GenericAPIView和5个视图拓展类的组合

通过from rest_framework.generics import 导入,写视图类就只用继承视图子类

  1. ListAPIView,只用于展示所有
  2. CreateAPIView,添加一条
  3. ListCreateAPIView,展示所有和添加一条
  4. RetrieveAPIView,展示一条
  5. DestroyAPIView,删除一条
  6. UpdateAPIView,修改一条
  7. RetrieveUpdateDestroyAPIView,展示、修改、删除一条
  8. RetrieveDestroyAPIView,展示一条,删除一条
  9. RetrieveUpdateAPIView,展示一条,修改一条

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

1.1 视图类

想写 publish: 查询所有,查询单条,修改一条,新增一条,删除一条的接口

class PublishView(ListCreateAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer


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

1.2 路由

路由没变

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

2 视图集

将使用同一个库和序列化类的视图整合起来

2.1 ModelViewSet

视图函数
from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
    queryset = Publish.objects.all()
    serializer_class = PublishSerialize
路由
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源码分析

  1. 有查询所有接口
    get–list----》拿到所有数据,序列化–返回

  2. 新增一条
    post—create—》之前咱们写的新增的代码一样的

2.2 ViewSetMixin

ModelViewSet中继承了五个视图拓展类和GenericViewSet,GenericViewSe继承了ViewSetMixin,它重写了as_view()

ViewSetMixin 决定了,以后路由写法就变了

源码分析
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 在视图类写自定义方法

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

from rest_framework.viewsets import ViewSetMixin,ViewSet

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

  1. ViewSetMixin + APIView = ViewSet
    没有表相关直接使用ViewSet即可
  2. GenericViewSet + ViewSetMixin = ModelViewSet
    有与表相关则用ModelViewSet
视图类
class UserView(ModelViewSet):
    queryset = UserInfo.objects.all()
    serializer_class = UserSerializer

    def book(self, request):
        return Response('from book')
路由
path('book/', UserView.as_view({'post': 'login'}))
访问地址

在这里插入图片描述

2.3 ReadOnlyModelViewSet

from rest_framework.viewsets import ReadOnlyModelViewSet

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

2.4 视图层中类的总结

1 两个视图基类

APIView和GenericAPIView

  1. APIView的执行流程:
    包装了新的 处理了csrfrequeset,执行了3大认证,处理全局异常
  2. GenericAPIView
    要做序列化,要跟数据库打交道,就直接继承它即可
    1. 类属性 querysetserializer_class
    2. 方法 get_objectget_querysetget_serializer
2 5个视图扩展类(不是视图类)

需要GenericAPIView才能用

  1. RetrieveModelMixin
    查询一条,写了一个方法retrieve,代码就是 跟咱们之前写获取单条get方法内容一样
  2. CreateModelMixin
    新增一条写了一个方法create,代码就是 跟咱们之前写新增一条 post 方法内容一样
  3. DestroyModelMixin
    删除一条写了一个方法destroy,代码就是 跟咱们之前写删除一条 delete 方法内容一样
  4. ListModelMixin
    查询所有写了一个方法list,代码就是 跟咱们之前写查询所有 get 方法内容一样
  5. UpdateModelMixin
    修改一个写了一个方法update,代码就是 跟咱们之前写修改一条put 方法内容一样
3 9个视图子类

继承GenericAPIView+5个视图扩展类的组合
参考1

视图集
  1. ModelViewSet:
    ViewSetMixin+GenericAPIView+5个视图扩展类
    GenericViewSet+5个视图扩展类

  2. ViewSetMixin源码:路由做映射的配置,以后视图类中方法可以随便命名
    Viewset:ViewSetMixin+APIView—》不需要要序列化,路由写法变了
    GenericViewSet:ViewSetMixin+GenericAPIView–》需要序列化,需要用数据库,路由写法变化
    ReadOnlyModelViewSet:list和retrieve

3 路由

之前的路由写起来,做映射,可能有些麻烦,于是drf,帮咱们封装了两个路由类—》可以帮助咱们快速生成之前咱们写的映射关系

条件:必须是继承ViewSetMixin+APIView及其子类才能自动生成

自动生成路由:自动映射如下:

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

3.1 使用方法

大前提:视图类必须是继承ViewSetMixin+APIView及其子类才能自动生成

使用步骤

#### 1 导入路由类
from rest_framework.routers import SimpleRouter, DefaultRouter

#### 2 类实例化得到对象
router = SimpleRouter()

#### 3 自动生成路由,调用对象的某个方法,完成跟视图类的对应关系,映射路由
router.register('publish', PublishView, 'publish')
router.register('user',UserView,'user')

##### 4 把自动生成的路由,加到总路由中
urlpatterns = urlpatterns + router.urls  # 两个列表直接相加

### 第四步可以这样写,在urlpatterns 中
	# 给路由加前缀
	path('api/v1/', include(router.urls)),   
	# http://127.0.0.1:8008/api/v1/user/register/--->post

3.2 SimpleRouter, DefaultRouter

SimpleRouter, DefaultRouter区别

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

以后就用:SimpleRouter就可以

3.3 action装饰器

在视图类写自定义方法,大致实现如2.2.1
路由不用变,在视图类中定义并使用action装饰器

使用方法
from rest_framework.decorators import action
class UserView(ModelViewSet):
    queryset = UserInfo.objects.all()
    serializer_class = UserSerializer

	@action(methods=['POST'], detail=False)
	def register(self, request):
		back_dic = {'code': 200, 'msg': "注册成功"}
		ser = self.get_serializer(data=request.data)
		if ser.is_valid():
		    ser.save()
		    return Response(back_dic)
		else:
		    return Response({'code': 200, 'msg': ser.errors})
访问地址

通过特定的访问地址和post方法即可使用register方法,
其中user是使用这个类的地址
在这里插入图片描述

action参数
  1. methods:请求方式,可以写多个
  2. detail:路径中是否带id号
    http://127.0.0.1:8008/user/register/       detail=False
    http://127.0.0.1:8008/user/4/register/       detail=True

3.4 重写方法

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

重写list
class UserView(ModelViewSet):
    queryset = UserInfo.objects.all()
    serializer_class = UserSerializer

	# 以后可能会重写list,做自己的定制
    def list(self, request, *args, **kwargs):
        res = super().list(request, *args, **kwargs)
        return Response({'code': 200, 'msg': '查看所有用户成功', 'result': res.data})
重写get_serializer_class

是GenericAPIView类中的方法,返回什么,以后就以哪个序列化类继续操作

class UserView(ModelViewSet):
    queryset = UserInfo.objects.all()
    serializer_class = UserSerializer

    def get_serializer_class(self, *args, **kwargs):
        if self.action == 'login':
            return LoginSerializer
        else:
            return self.serializer_class
    
    @action(methods=['POST'], detail=False)
    def login(self, request):
        back_dic = {'code': 200, 'msg': "登录成功"}
        
        # 使用序列化类
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            for i in self.get_queryset():
                if i.username == ser.data.get('username') and i.password == ser.data.get('password'):
                    return Response(back_dic)

            back_dic['code'] = 1002
            back_dic['msg'] = "用户密码错误"
            return Response(back_dic)
        else:
            return Response({'code': 200, 'msg': ser.errors})   

重写perform_create

数据保存前,做一些操作,比如写日志

def perform_create(self, serializer):
    serializer.save()

3.4 视图类的对象中的action参数print(self.action)

视图类的对象中有个action属性—》它是单次请求执行的方法名的字符串

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值