DRF---CBV,APIView和Request源码分析,序列化类

CBV源码分析


从路由开始

path('books/', views.BookViwe.as_view())

views.BookViwe.as_view()的执行结果,是函数内存地址,进入as_view()函数查看,发现它返回的是view这个函数的内存地址。

def as_view(cls, **initkwargs):
    def view(request, *args, **kwargs):
    	return self.dispatch(request, *args, **kwargs) 
    return view

所以请求来的时候,路由匹配成功,就会去执行as_view里的view函数。

def view(request, *args, **kwargs):
    	return self.dispatch(request, *args, **kwargs) 

执行view函数返回的是self.dispatch(request),而dispatch是CBV最精髓的部分,它的作用就是你是什么请求,就会执行视图类中请求名字的方法。

def dispatch(self, request, *args, **kwargs):
    	# 请求方法变成小写字符串  ,如果是get请求,就是 'get'
        # self.http_method_names  列表 ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
      if request.method.lower() in self.http_method_names:
        	# 重点:反射,去对象中,根据字符串,取出方法或属性
          	# 'get'--->self是视图类的对象--》handler就是你写在视图类中的get方法
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        # 执行get方法---》视图函数的get方法
        return handler(request, *args, **kwargs)

小结: 发送请求–>as_view()–>as_view中的view函数–>dispatch函数–>执行函数,返回结果。

APIView的基本使用


如果使用了drf,以后写的都是cbv,但是都是继承drf提供的视图类,APIView

from rest_framework.views import APIView

class BookViwe(APIView):
    def get(self,request):
        # return HttpResponse('hello web') # 以后不要用django原生的响应了:四件套:render,HttpResponse,Redirect,JsonResponse
        return Response('hello web') # drf提供的响应--》放字符串,字典,列表:HttpResponse+JsonResponse结合体

drf是个app,是需要注册的,去settings里添加INSTALLED_APPS。

INSTALLED_APPS = [
		...
    'rest_framework'   # 一定不要忘了注册
]
"""
需要注意点的点:
	app要加上逗号
	不可以使用使用三引号加注释
"""

补充知识:

django项目中app的作用:django是一个大而全的框架,内置了很多的app帮我们完成了很多的事情,比如说数据库的迁移自动生成的很多表。

INSTALLED_APPS = [
    'django.contrib.admin',  # 后台管理,系统自带后台管理admin
    'django.contrib.auth',   # 权限管理--》生成6张表
    'django.contrib.contenttypes',# 对所有app的表进行记录的
    'django.contrib.sessions',   # session功能--》django-session表---》app
    'django.contrib.messages',  # django消息框架---》flask的闪现
    'django.contrib.staticfiles', #  静态资源
    'app01.apps.App01Config',
    'rest_framework',   # 一定不要忘了注册   
]

APIView执行流程分析


也是先从路由开始

path('books/', views.BookViwe.as_view())

views.BookViwe.as_view()的执行结果,是函数内存地址----》view这个函数的内存地址

但是现在的as_view已经不是django原生View的as_view了,而是drf的APIView的as_view了。因为自己写的类继承了APIView,面向对象中 属性查找顺序是先从自己找,再从产生对象的类中找,再去类的父类中找,所以先找到的是APIView里重写的as_view方法。

def as_view(cls, **initkwargs):  # as_view是django的View的派生方法
    	# 这个view就是原生django中View类的view,还是原来的view
        view = super().as_view(**initkwargs)
        # csrf_exempt(view)的作用就是把csrf校验全去掉了,之后就不需要去注释掉中间件中的csrf了,就类似于给view加了一个csrf_exempt装饰器。
        # 它就是装饰器的本质:把被装饰的函数当做参数,传入装饰器函数,返回值赋值给被装饰的函数
        return csrf_exempt(view)

重点:view还是调用的View里的view,只是不需要处理csrf了。

dispatch已经不是django原生View的dispatch了,是drf的APIView的dispatch了也是和查找的顺序有关,也是先找到APIView里的dispatch方法。

  def dispatch(self, request, *args, **kwargs):
	    # 包装了新的request对象--》以后视图类中用的request对象,就是新的request
        request = self.initialize_request(request, *args, **kwargs)

        try:  # 捕获了异常
          	# 内部执行了三大认证:认证(登陆认证),频率(1分钟只能访问接口3次),权限(普通用户不能访问,超级用户才能访问)
            self.initial(request, *args, **kwargs)
            # 原来dispatch的代码,重写了一下---》执行视图函数
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs) # 执行视图函数

        except Exception as exc:
          	# 处理了异常,统一异常处理---》返回固定格式
            response = self.handle_exception(exc)
				# 包装了response对象,响应对象,浏览器看到好看的样子,postman只看到json
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

重点:

  1. drf:包装了新的request对象(drf的Request的对象了),已经不是django 的request对象了

     # rest_framework.request.Request   以后新的request
            # django.core.handlers.wsgi.WSGIRequest  django原来的
    
  2. 在执行视图函数之前,执行了三大认证

  3. 处理了全局异常 ---》执行三大认证期间,执行视图函数期间,如果出了错,都能统一处理

  4. 包装了响应对象

Request对象源码分析


以后视图类中使用的request对象,是rest_framework.request.Request的对象。

class Request:
  	#1 把老的request放到了新的request的_request属性了
    # 新的request--》request._request  是老的
  	-__init__:    self._request = request(这个request是老的)
      
     #2 以后新的request用起来跟原来一样用
    	# 取出原来老request的属性,以下方法取,麻烦 
      	'''
      	request._request.POST
        request._request.GET
        request._request.method
        '''
        # 重写了__getattr__ 魔法方法,. 拦截  --》对象.属性如果属性不存在,触发这个方法执行		
        # 新的request.POST,新的request中没有POST,触发Request类的__getattr__ 
        def __getattr__(self, attr):
          try:
            	# 通过反射,去拿老request的属性或方法
              return getattr(self._request, attr)
          except AttributeError:
              return self.__getattribute__(attr)
  
  	# 3 新的request有个data方法,包装成了数据属性
    	-前端无论什么编码方式传得body体中的数据,都从request.data中取,当字典用即可
      	-原生djagno,如果是formdata,urlencoded是从POST中取,如果是json,从body中取出来自己转
        
    # 4  新的request有个query_params方法,包装成了数据属性
      	-就是原来老的request的GET属性
      
    # 5 上传文件,跟之前一样用,但是人家重写了

新的request重点:

  1. 老的request是新的request._request
  2. 跟原来一样用
  3. body提交的数据都从request.data中取
  4. 请求地址中的数据都从request.query_params中取

序列化类Serializer的使用


序列化组件就是一个类,可以完成下面的事:

  1. 序列化,把模型对象(book,queryset)转换成字典,经过drf的response以后变成json字符串
  2. 反序列化,把客户端发送过来的数据(前端json格式字符串),经过request.data以后变成字典,序列化器可以把字典转成模型,存到数据库
  3. 反序列化,完成数据校验功能---》前端传入的数据,长短,是否是邮箱,手机号。。可以做校验

使用

# 路由
 path('books/', views.BookAPIView.as_view()),
# 视图类
from .models import Book
from .serializer import BookSerializer
class BookAPIView(APIView):
    def get(self,request):
        # 取出所有图书的qs对象
        books=Book.objects.all()
        # 借助于序列化类--》写一个序列化类
        # 类实例化时:instance:要序列化的对象   many:True 多条 先记着这两个参数
        ser=BookSerializer(instance=books,many=True)
        # ser.data  完成了序列化
        print(ser.data)  # 把qs对象,转成了字典,根据序列化类中你写的字段转的
        return Response(ser.data)

# 序列化类
from rest_framework import serializers

class BookSerializer(serializers.Serializer):  # 一定要继承Serializer
    # 写要序列化的字段,比如,不想把作者给前端
    name = serializers.CharField()  # 字段类,跟models中一一对应
    price = serializers.IntegerField()  # 字段类,跟models中一一对应
    publish = serializers.CharField()  # 字段类,跟models中一一对应
    author = serializers.CharField()  # 字段类,跟models中一一对应

序列化类常用字段和字段参数


字段类

### 字段类:跟models一一对应,但是比它多
# BooleanField 	
# NullBooleanField 	
# CharField 	
# EmailField
# RegexField 
# SlugField 
# URLField 	
# UUIDField 	
# IPAddressField 	
# IntegerField 	
# FloatField 
# DecimalField 
# DateTimeField 	
# DateField 	
# TimeField 	
# ChoiceField 	
# FileField 	
# ImageField 	

------ 以上都是models有的----下面是serializer独有的---
# ListField 	
# DictField 

字段属性

#### 字段属性--->写在字段类中的---》干啥用?反序列化校验用的!!!!
## 选项参数
# CharField
max_length 	最大长度
min_lenght 	最小长度
allow_blank 	是否允许为空
trim_whitespace 	是否截断空白字符

# IntegerField
max_value 	最小值
min_value 	最大值

# 通用参数:
### 重点讲
read_only 	表明该字段仅用于序列化输出,默认False
write_only 	表明该字段仅用于反序列化输入,默认False


required 	表明该字段在反序列化时必须输入,默认True
default 	反序列化时使用的默认值
allow_null 	表明该字段是否允许传入None,默认False
error_messages 	包含错误编号与错误信息的字典
posted @   早安_1207  阅读(91)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
返回顶端
点击右上角即可分享
微信分享提示