9视图子类 2个视图集 路由系统自动生成路由 action装饰器 认证组件登入接口

回顾

# 1 前后端开发模式
	-分离和混合
    -http 通信   后端都是web后端
    -前端:pc桌面开发,web开发,app,小程序   ----》http----》调用后端----后端都是一套
# 2 api接口

# 3 接口测试工具
# 4 restful规范 10条
# 5 drf介绍,快速使用
# 6 cbv 执行流程
# 7 APIView执行流程
# 8 Request对象源码
# 9 序列化和反序列化
# 10 序列化组件---》写类继承,实例化得到对象
	-常用字段和字段参数
	-做序列化
    	-序列化类实例化---》对象---》传入要序列化的数据,many----》ser.data
        -source
        -SerializerMethodField    
        -在表模型中写方法
        -ListField
        -DictField
    -做反序列化
    	-新增
        	-序列化类实例化---》对象---》传入前端的数据----》数据校验---》ser.save
            -数据校验:字段自己,局部,全局钩子
        -保存
        	-序列化类实例化---》对象---》传入前端的数据和要修改的数据----》数据校验---》ser.save
            -数据校验:字段自己,局部,全局钩子
            
        -重点:
        	有时候,序列化字段和反序列化字段,不一样
        	-定制的序列化字段,不能用来反
            -read_only和write_only 的使用
    -数据校验
    	-字段自己
        -局部
        -全局
        
        
   -ModelSerializer,跟表有关系
	-不用重写create和update
    -字段可以映射过来  
    -重写字段
    -给字段类传参数---》extra_kwargs
    -定制字段,跟之前一模一样
    -fields 列表,必须要有所有字段(序列化,反序列化都要注册----》一定是表模型的字段吗?)
    
    
 # 11 请求与响应
	-Request 源码
    -能够解析的编码格式
    	-全局配置
        -局部配置
    -Response 源码
    -能够响应的编码格式
    	-全局
        -局部
        
    -drf向响应头中写数据
    -原生django向响应头中写数据
    obj=HttpResponse()  ---->obj['xx']=yy
        
        
 # 12 视图  View
	-两个视图基类:APIView   GenericAPIView
    -APIView
    	-执行流程:新的reqeust,三大认证,全局异常
        -重写了as_view,dispatch
        -类属性:parser_class,xxx
        
    -GenericAPIView---》继承了APIView----》以后,如果是跟数据库打交道,尽量用它
    	1 queryset:要序列化或反序列化的表模型数据
        2 serializer_class:使用的序列化类
        3 lookup_field :查询单条的路由分组分出来的字段名
        4 filter_backends:过滤类的配置(了解)
        5 pagination_class:分页类的配置(了解)

        # 方法
        1 get_queryset   :获取要序列化的对象
        2 get_object  :获取单个对象
        3 get_serializer :获取序列化类  ,跟它差不多的get_serializer_class,一般重写它,不调用它
        4 filter_queryset  :过滤有关系(了解)
        
        
    
    -补充,根据请求方式,定制序列化类
     def get_serializer(self, *args, **kwargs):
        if self.request.method=='GET':
            return 序列化单条的序列化类
        else:
            return 新增的序列化类
        
        
        
        
 #13 5 个视图扩展类----》不是视图类----》必须配合GenericAPIView
	-每个类自己写了一个方法,写的不是【请求方式,不是put,get。。。】的方法,写的是list,destroy。。。
    -minxin 混入,通过多继承来实现多个功能
    -from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin,
    ListModelMixin
    
    
    -继承GenericAPIView+某个视图扩展类+请求方式的方法

9个视图子类

# 两个视图基类
# 5个视图扩展类
# 9个视图子类 --->>> 视图类,不需要额外继承GenericAPIView,只需要继承9个中其中某个,就会有某个或某几个接口

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

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


# 新增一个,修改一个,删除一个
class BookDetailView(RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

2个视图集

通过ModelViewSet编写5个接口

# 路由
urlpatterns = [
    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个只读接口

# 路由
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源码分析

# 请求来了,路由匹配成功
--->get请求,匹配成功books,会执行views.BookView.as_view({'get': 'list', 'post': 'create'})()
------>读as_view【这个as_view是ViewSetMixin的as_view】

    @classonlymethod
    def as_view(cls, actions=None, **initkwargs):
        # 如果没有传actions,直接抛异常,路由写法变了后,as_view中不传字典,直接报错
        if not 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 = cls(**initkwargs)
            if 'get' in actions and 'head' not in actions:
                actions['head'] = actions['get']
            self.action_map = actions
            for method, action in actions.items():
                handler = getattr(self, action)
                setattr(self, method, handler)

            return self.dispatch(request, *args, **kwargs)
        # 去除了csrf校验
        return csrf_exempt(view)
    
    
# 路由匹配成功执行views.BookView.as_view({'get': 'list', 'post': 'create'})()----》本质执
行ViewSetMixin----》as_view----》内的view()---》代码贴过来
    def view(request, *args, **kwargs):
            #actions 是传入的字典--->{'get': 'list', 'post': 'create'}
            self.action_map = actions
            # 第一次循环:method:get,action:list
            # 第一次循环:method:post,action:create
            for method, action in actions.items():
                # 反射:去视图类中反射,action对应的方法,action第一次是list,去视图类中反射list方法
                # handler就是视图类中的list方法
                handler = getattr(self, action)
                # 反射修改:把method:get请求方法,handler:list
                # 视图类的对象的get方法,变成了list
                setattr(self, method, handler)

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

image-20230206162201395

image-20230206162312689

from rest_framework.viewsets包下的类

'''
from rest_framework.viewsets下有这几个类
ModelViewSet:5个试图扩展类+ViewSetMixin+GenericAPIView
ReadOnlyModelViewSet::2个试图扩展类+ViewSetMixin+GenericAPIView   只读的两个
ViewSetMixin:魔法,重新了as_view,只要继承他,以后路由写法变成了映射方法
ViewSet:ViewSetMixin+ APIView
GenericViewSet:ViewSetMixin+ GenericAPIView
'''


#重点:
	以后,你要是想继承APIView,但是想变路由写法【视图类中方法名任意命名】,要继承ViewSet
    以后,你要是想继承GenericAPIView,但是想变路由写法【视图类中方法名任意命名】,要继承GenericViewSet

视图层大总结

1. 两个视图基类
	APIVIew、GenericAPIView
  
2. 5个视图扩展类,不是视图类,必须配合GenericAPIView

3. 9个视图子类,是视图类,只需要继承其中某一个即可

4. 视图集
	ModelViewSet: 路由写法变了,只需要写两行,5个接口都有了
  ReadOnlyModelViewSet:路由写法变了,只需要写两行,2个只读接口都有了
  ViewSetMixin:不是视图类,是一个魔法(源码中注释this is  the magic),重写了as_view,路由写法变了,变成映射了
  	views.BookView.as_view({'get': 'list', 'post': 'create'})
    ViewSet:ViewSetMixin + APIView
    GenericAPIViewSet: ViewSetMixin + GenericAPIView
      
# 补充:
举例子:发送短信接口,视图类叫SendView,方法叫send_sms,路由配置变了
	get --->>> 映射是send_sms
  class SendView(ViewSet):
    def send_sms(self, request):
      pass

image

路由系统

自动生成路由

# drf 由于继承ViewSetMixin类,路由写法变了
	原生 + drf,以后的路由写法,可能会有如下情况(三种情况)
  	1. path('book/', views.BookView.as_view())
  	2. path('book/', views.BookView.as_view({'get': 'list', 'post': 'create'}))
  	3. 自动生成
  
# drf提供了两个路由类,视图类只要继承了ModelViewSet后,路由可以自动生成

# 使用步骤:
	# 第一步:导入路由类
  	from rest_framework.router import SimpleRouter, DefaultRouter
    
  # 第二步:实例化得到对象(有两个类,一般使用SimpleRouter)
  
  # 第三步:注册:router.register('books', views.BookView, 'books')
  	就相当于路径类跟视图类做绑定关系,有几个视图类就要写几次。
    第一个参数就是路径,第二个就是视图类(根据视图类自动产生books的路径),第三个参数就是别名(一般跟路径相同)# 第四步:在ulrpatterns中注册,有两种方式
  	方式1. urlpatterns += router.urls
    方式2. include方式(得导include): path('api/v1/', include(router.ulrs)) 此种方式多一些
      
      
# 底层实现:自动生成路由就做了
	本质是自动做映射,能够自动生成的前提是,视图类中要有5个方法中的某一个或多个
  	get --->>> list
    get --->>> retrieve
    put --->>> create
    delete --->>> destory
  ModelViewSet、ReadOnlyModelViewSet可以自定生成
  
  9个视图类 + 配合ViewSetMixin	才可以自动生成
  
  GenericAPIView + 5个视图扩展类 + 配合ViewSetMixin 才能自动生成

image-20230206173008311

DefaultRouter的方式有多种

image-20230206181055319
在urlpatterns中使用include,定义前缀。如图是故意输错路径,查看使用类DefaultRouter的多种方式
image-20230206180852063

SimpleRouter的方式就比较少

image-20230206181459241

image-20230206181406441

action 装饰器

用来控制get、post、put... 映射给谁,是映射给继承了mixins类里面的create、list、retrieve,还是映射给你视图类里面自定义的方法(因为没有action装饰器,在自动创建路路由时,是无法对应映射关系,它只会默认对应继承类里面create、list、destroy...)

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

# 使用步骤
	1. 写在视图类方法上
  class sendView(ViewSet):
    @action(method=['POST'], detail=False) 
    '''
    methods指定请求方法,可以传多个 
    detail:只能传True和False 
    False,不带id的路径:send/send_sms/ 
    True,带id的路径:send/2/send_sms/
    url_path:生成send后路径的名字,默认以方法名命名
    url_name:别名,反向解析使用(了解)
    '''
    def send_sms(slef, request, pk(当detail为True携带pk)):
      print('发送成功,%s' % phone)
      return Response({'code': 100, 'msg': '发送成功'})

# 以后看到的drf路由写法
	后期都是自动生成的,在router.register注册,在一般不在urlpatterns加路由了

image-20230206203901711

image-20230206203914850

True,带id的路径:send/2/send_sms/

image-20230206205332327

image-20230206205556517

补充

# 补充:
	1. 不同请求方式可以用不同序列化类
	2. 不同action使用不同序列化类
class SendView(GenericViewSet):
  queryset = None
  serizlalizer_class = '序列化类'
  
  def get_serializer(self, *args, **kwargs):
    if self.action == 'lqz': # 更细力的去区分判断哪个该用哪个序列化类,而如果用request.method就都是GET
      # action 是在ViewSetMixin里加进来的
      return '某个序列化类'
    elsereturn '另一个序列化列'
    
  @action(method=['GET'], detail=True)
  def send_sms(self, request, pk):
    print(pk)
    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(method=['GET'], detail=True)
  def login(self, request):  # get
    # 序列化类
    pass

action所在位置
image-20230206212157231

认证组件

访问某个接口,需要登入后才能访问

第一步:写个登入功能,用户表
User表
userToken表:存储用户登录状态(这个表可以没有,如果没有,把字段直接写在User表上也可以)

登入接口

# 表模型

class User(models.Model):
  username = models.CharFiled(max_length=32)
  password = mdoels.CharFiled(max_length=32)
  
class UserToken(mdoels.Model):
  token = models.CharField(max_length=32)
  user = models.OneToOneField(to='User', on_delete=models.CASCADE, null=True)
  # user:反向,表名小写,所以有user字段
  
# 路由
router.register('user', view.UserView, 'user')
# api/v1/user/login	post请求

# 视图类
登录接口 自动生成路由 + 由于登录功能,不用序列化,所以继承ViewSet
from .models import User, UserToken
import uuid

class UserView(ViewSet):
  @action(methods=['POST'],detail=False)
  def login(self, request):
    username = request.data.get('username')
    password = request.data.get('password')
	  User.objects.filter(username=username, password=password).first()
    if user:
      # 用户存在,登录成功
      # 生成一个随机字符串 --->>> uuid
      token = str(uuid.uuid4())  # 生成一个永不重复的随机字符串
      # 在userToken表中存储一个:
      	1.从来没有登录过,插入一条数据
        2.登录过了,修改记录
      # 如果有就修改,如果没有就新增,得加if判断
      # Kwargs 传入的东西查找,能找到,使用defaults的更新,否则新增一条
      userToken.objects.update_or_create(user=user, defaults={'token': token})
      return Response({'code': '100', 'msg': '登录成功''token': token})
    else:
      return Response({'code': '101', 'msg': '用户名或密码错误'})

认证功能

posted @   小福福  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
  1. 1 原来你也在这儿 温余福
  2. 2 世间美好和你环环扣扣 温余福
  3. 3 随风起舞 温余福
  4. 4 罪恶都市 温余福
罪恶都市 - 温余福
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 王星

作曲 : 灰鸿啊/皮皮

编曲 : 夏日入侵企画

制作人 : 邢硕

节奏吉他 : 肯尼

主音吉他 : 张伟楠

贝斯 : 皮皮

鼓 : 海鑫

和声 : 邢硕

音效制作 : 邢硕

录音 : 邢硕/夏国兴

混音 : 于昊

特别鸣谢 : 张伟楠

这城市的车流和这地表的颤抖

像一颗石子落入地心之后泛起的温柔

暗涌

河水流过转角她的楼

被梦魇

轻声呓语唤醒身后的幼兽

失效感官焦灼只剩下

麻木愚钝无从感受

共同支撑全都瓦解

只是我们现在都

已忘记到底是

谁隐藏春秋

谁在大雨之后

把旗帜插在最高的楼

过去陈旧的还在坚守

内心已腐朽

摇摇欲坠不停退后

毁灭即拯救

夏日掠夺春秋

结局无法看透

眼看这情节开始变旧

所有的城池已失守

最终无法占有

无眠辗转

伴着人间破碎的旧梦

像繁星

退却后只剩下混沌的夜空

炙热

掩盖风声鹤唳的担忧

把所有失落无助反手推入

无尽的白昼

失效感官焦灼只剩下

麻木愚钝无从感受

共同支撑全都瓦解

只是我们现在都已经忘记到底是

谁隐藏春秋

谁在大雨之后

把旗帜插在最高的楼

过去的陈旧还在坚守

内心已腐朽

摇摇欲坠不停退后

毁灭即拯救

夏日掠夺春秋

结局无法看透

眼看这情节开始变旧

所有的城池早已失守

惶恐难以接受

缠绵往复不肯放手

最终无法占有

谁隐藏春秋

谁在大雨之后

把旗帜插在最高的楼

过去的陈旧还在坚守

内心已腐朽

摇摇欲坠不停退后

毁 灭 即 拯 救

谁掠夺春秋

谁在大雨之后

把旗帜插在最高的楼

过去的陈旧还在坚守

内心已腐朽

摇摇欲坠不停退后

毁灭即拯救

夏日掠夺春秋

结局无法看透

明知城池已失守

缠绵往复不肯放手

最终无法占有

点击右上角即可分享
微信分享提示