drf-6

9个视图子类

# 两个视图基类
# 5个视图扩展类
# 9个视图子类---->视图类,不需要额外继承GenericAPIView,只需要继承9个中其中某个,就会有某个或某几个接口
#路由
urlpatterns=[
  path('books/',views.BookView.as_view()),
  path('books/<int:pk>/',views.BookView.as_view()),
]

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

视图集

2.1通过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

2.2通过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

2.3ViewSetMixin源码分析

# 请求来了,路由匹配成功---》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 以后视图类类中的方法名,可以任意命名,只要在路由中做好映射即可【重要】

img

img

2.4 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

2.5 视图层大总结

# 1 两个视图基类
APIView,GenericAPIView
# 2 5个视图扩展类,不是视图类,必须配合GenericAPIView
# 3 9个视图子类, 是视图类,只需要继承其中某一个即可
# 4 视图集
	-ModelViewSet:路由写法变了,只需要写两行,5个接口都有了
    -ReadOnlyModelViewSet:路由写法变了,只需要写两行,2个只读接口都有了
    -ViewSetMixin:不是视图类,魔法,重写了as_view,路由写法变了,变成映射了
    	views.BookView.as_view({'get': 'list', 'post': 'create'})
    -ViewSet:ViewSetMixin+ APIView
	-GenericViewSet:ViewSetMixin+ GenericAPIView

# 举例子:发送短信接口,视图类叫SendView,方法叫Send_sms, 路由配置变了
get--->send_sms
class SendView(ViewSet):
  def send_sms(self, request):
    

img

路由系统

3.1自动生成路由

# 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 才能自动生成

img

DefaultRouter的方式有多种

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

SimpleRouter的方式就比较少

img

img

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加路由了

img

img

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

img

img

补充

# 补充:
	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所在位置
img

认证组件

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

第一步:写个登入功能,用户表
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 @   hugmi男孩  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
  1. 1 原来你也在这里 周笔畅
  2. 2 世间美好与你环环相扣 柏松
  3. 3 起风了 吴青峰
  4. 4 极恶都市 夏日入侵企划
起风了 - 吴青峰
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 米果

作曲 : 高橋優

编曲 : 刘胡轶/貢多杰

制作人 : 刘胡轶/吴青峰

配唱制作人 : 刘胡轶

乐器监制 : 刘胡轶

吉他 : 胡晨

贝斯 : 甯子达

弦乐录音棚 : 中国剧院录音棚

录音工程师 : 倪涵文/李游/李杨/邢铜/韩宽/李巍

录音监制 : 倪涵文/李游

混音&母带工作室 : OKmastering studio

混音&母带工程师 : 全相彦

制作协力 : 刘西洋

制作发行 : 智慧大狗 × 天才联盟

出品人 : 张葛

监制 : 崔恕/王明宇

弦乐监制 : 李朋

弦乐 : 国际首席爱乐乐团

鼓(打击乐):祁大为

和音编写&演唱:鱼椒盐

人声&吉他&鼓(打击乐)录音棚:55Tec studio

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

这一路上走走停停

这一路上走走停停

顺着少年漂流的痕迹

迈出车站的前一刻

竟有些犹豫

不禁笑这近乡情怯

不禁笑这近乡情怯

仍无可避免

而长野的天

依旧那么暖

风吹起了从前

从前初识这世间

从前初识这世间

万般流连

看着天边似在眼前

也甘愿赴汤蹈火去走它一遍

如今走过这世间

如今走过这世间

万般流连

翻过岁月不同侧脸

措不及防闯入你的笑颜

我曾难自拔于世界之大

我曾难自拔于世界之大

也沉溺于其中梦话

不得真假 不做挣扎 不惧笑话

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

逆着光行走 任风吹雨打

短短的路走走停停

短短的路走走停停

也有了几分的距离

不知抚摸的是故事 还是段心情

也许期待的不过是 与时间为敌

再次看到你

微凉晨光里

笑得很甜蜜

从前初识这世间

从前初识这世间

万般流连

看着天边似在眼前

也甘愿赴汤蹈火去走它一遍

如今走过这世间

如今走过这世间

万般流连

翻过岁月不同侧脸

措不及防闯入你的笑颜

我曾难自拔于世界之大

我曾难自拔于世界之大

也沉溺于其中梦话

不得真假 不做挣扎 不惧笑话

我曾将青春翻涌成她

我曾将青春翻涌成她

也曾指尖弹出盛夏

心之所动 且就随缘去吧

晚风吹起你鬓间的白发

晚风吹起你鬓间的白发

抚平回忆留下的疤

你的眼中 明暗交杂 一笑生花

我仍感叹于世界之大

我仍感叹于世界之大

也沉醉于儿时情话

不剩真假 不做挣扎 无谓笑话

我终将青春还给了她

连同指尖弹出的盛夏

心之所动 就随风去了

以爱之名 你还愿意吗

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