首页 > 编程语言 >反序列化类校验部分源码解析 断言 drf之请求 drf之响应 视图组件介绍及两个视图基类 基于GenericAPIView+5个视图扩展类

反序列化类校验部分源码解析 断言 drf之请求 drf之响应 视图组件介绍及两个视图基类 基于GenericAPIView+5个视图扩展类

时间:2023-02-05 19:44:34浏览次数:40  
标签:self request 视图 序列化 data drf

  • 反序列化类校验部分源码解析(了解)

  • 断言

  • drf之请求

  • drf之响应

  • 视图组件介绍及两个视图基类

  • 基于GenericAPIView+5个视图扩展类

昨日内容回顾

# 1 序列化类的常用字段
    -CharField
    ...
    -ListField
    -DictField
    
# 2 字段参数
    -max_length...
    -min_length...
    -required,default...
    -read_only,write_only
    
# 3 定制序列化字段(改名字)
    -source这个字段参数
    -如果是表模型自己的字段,直接写
    -如果是关联表字段,通过外键.拿到
    
# 4 定制序列化字段(格式更丰富)
    -在序列化类中使用:SerializerMethodField,配合一个 get_字段名的方法,方法返回什么,这个字段就是什么--->这种字段以后不能用来做反序列化了
    -在表模型中使用,写方法的方式,方法返回什么,这个字段就是啥,序列化类中需要配合ListField,DictField--->这种字段以后不能用来 做反序列化了
    -方法可以包装成数据属性,也可以不包装
    
# 5 反序列化校验几层
    -1 字段自己的校验规则:序列化类字段参数控制的
    -2 每个字段单独设置校验方法(了解)
    -3 局部钩子
    -4 全局钩子
    
# 6 ModelSerializer:继承自Serializer
    class BookSerializer(ModelSerializer):
        # 如果字段是映射过来的,也会把字段属性[反序列化校验规则],也会映射过来,有可能会校验失败,不能写入
        # 咱们重写这个字段,不加任何规则,取消掉它
        name = serializer.CharField()
        class Meta:
            model=Author
            # fields="__all__"
            # 只要是序列化的字段和反系列化的字段,都要在这注册
            # 序列化的字段,可能不是表模型的字段,是咱自己写的方法
            # 序列化的字段,可能是使用SerializerMethodField,也要注册
            fields=['name','photo','gender','addr']
            extra_kwargs={} # 给字段类增加属性,read_only和write_only用的多
            
      gender=serializer.CharField()
      addr=serializer.CharField()
      局部钩子,全局钩子完全一样
      SerializerMethodField也一样
      create
      update
        

# 7 反序列化的字段,一定跟模型表的字段是对应的吗?不一定随意写

image

1 反序列化类校验部分源码解析(了解)

# 反序列化校验,什么时候,开始执行校验
	-视图类中的 ser.is_valid(),就会执行校验,校验通过返回True,不通过返回False
    
    
# 入口:ser.is_valid() 是序列化类的对象,假设序列化类是BookSerializer---》is_valid---》找不到,找到父类BaseSerializer中有 :【raise_exception:先注意】
   def is_valid(self, *, raise_exception=False):
    
        if not hasattr(self, '_validated_data'):
            try:
                # self序列化类的对象,属性中没有_validated_data,一定会走这句【核心】
                self._validated_data = self.run_validation(self.initial_data)
            except ValidationError as exc:
                self._validated_data = {}
                self._errors = exc.detail
            else:
                self._errors = {}

        if self._errors and raise_exception:
            raise ValidationError(self.errors)

        return not bool(self._errors)
# self._validated_data = self.run_validation(self.initial_data) 核心--》self序列化类的对象
	-切记一定不要按住ctrl键点击
    -真正的执行顺序是,从下往上找,找不到,再往上
    -最终从Serializer类中找到了run_validation,而不是Field中的run_validation
    
    
    def run_validation(self, data=empty):
        # 字段自己的,validates方法
        (is_empty_value, data) = self.validate_empty_values(data)
        if is_empty_value:
            return data
        # 局部钩子----【局部钩子】
        value = self.to_internal_value(data)
        try:
            
            self.run_validators(value)
            # 全局钩子--》如果在BookSerializer中写了validate,优先走它,非常简单
            value = self.validate(value)
 
        except (ValidationError, DjangoValidationError) as exc:
            raise ValidationError(detail=as_serializer_error(exc))

        return value
    
# 局部钩子  self.to_internal_value(data)    ---》self是BookSerializer的对象,从根上找
     def to_internal_value(self, data):
        ret = OrderedDict()
        errors = OrderedDict()
        fields = self._writable_fields
        # fields写在序列化类中一个个字段类的对象
        for field in fields:
            # self BookSerializer的对象,反射validate_name
            validate_method = getattr(self, 'validate_' + field.field_name, None)
            try:
                # 在执行BookSerializer类中的validate_name方法,传入了要校验的数据
               validated_value = validate_method(validated_value)
            except ValidationError as exc:
                errors[field.field_name] = exc.detail
          
            else:
                set_value(ret, field.source_attrs, validated_value)

        if errors:
            raise ValidationError(errors)

        return ret

image

2 断言

# 源码中大量使用try和断言

# 关键字assert: 作用的判断,断定你是xx,如果不是就抛异常

# 土鳖写法
name = 'qwe'
if name == 'qwe':
    print('对了')
else:
    print('错了')
  raise Exception('名字为qwe,不能继续走了')

# assert的断言写法
name = 'qwe'
assert name=='qwe'  # 断定是,如果不是,就抛异常
print('后续代码')

3 drf之请求

3.1 Request能够解析的前端传入的编码格式

# 需求是该接口只能接收json格式,不能接收其他格式

# 方式一:在继承自APIView及其子类的视图类中配置(局部配置)
# 总共有三个:from rest_framework.parsers import              JSONParser,FormParser,MultiPartParser
class BookView(APIView):
    parser_classes = [JSONParser]
    

image

# 方式二:在配置文件中配置(影响所有,全局配置)
  -django有套默认配置,每个项目都有个配置
  -drf有套默认配置,每个项目也有个配置---> 就在django的配置文件中

    REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
        # 'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        # 'rest_framework.parsers.MultiPartParser',
    ],
}

image

# 方式三:全局配了1个,某个视图类想要3个,怎么配?
  -只需要在视图类,配置三个即可
  -因为:先从视图类自身找,找不到,去项目的drf配置中找,再找不到,去drf默认的配置中找

3.2 Request类中有哪些属性和方法(学过)

# 视图类方法中的request
  -data
  -__getattr__
  -query_params

4 drf之响应

4.1 Response能够响应的编码格式

# drf 是django的一个app,所以要注册
# drf的响应,如果使用浏览器和postman访问同一个接口,返回格式是不一样的
  -drf做了个判断,如果是浏览器,好看一些,如果是postman只要json数据
    
# 方式一: 在视图类中写(局部配置)
  -两个响应类--->找--->drf的配置文件中找--->两个类
  -from rest_framework.renderers import
JSONRenderer,BrowsableAPIRenderer
  class BookView(APIView):
        renderer_classes=[JSONRenderer,]

image

# 方式二: 在项目配置文件中写(全局配置)
  REST_FRAMEWORK = {
      'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ],
}

image

# 方式三: 使用顺序(一般就用内置的即可)
     优先使用视图类中的配置,其次使用项目配置文件中的配置,最后使用内置的

4.2Resposne的源码属性或方法

# drf 的Response 源码分析
   -from rest_framework.response import Response
   -视图类的方法返回时,retrun Response,走它的__init__,init中可以传什么参数

# Response init可以传的参数
    def __init__(self,
                 data=None,
                 status=None,
                 template_name=None,
                 headers=None,
                 exception=False,
                 content_type=None)
    
-data:之前咱们写的ser.data 可以是字典或列表,字符串--->序列化后返回给前端--->前端在响应体中看到的就是这个
    
-status:http响应的状态码,默认是200,可以改
    -drf在status包下,把所有http响应状态码都写了一遍,常量
    -from rest_framework.status import HTTP_200_OK
    -Response('ddd',status=status.HTTP_200_OK)
    
-template_name:了解即可,修改响应模板的样子,
BrowsableAPIRenderer定死的样子,后期公司可以自己定制

-headers:响应头,http响应的响应头
     -考你,原生djagno,如何像响应头中加东西
     # 四件套 render,redirect,HttpResponse,JsonResponse
            obj = HttpResponse('dddd')
            obj['xxc'] = 'yyc'
            return obj
        
-content_type :响应编码格式,一般不动
       
# 重点:data,status,headers

image

5 视图组件介绍及两个视图基类

# drf 视图,视图类,学过APIView,drf的基类,drf提供的最顶层的类

# APIView跟之前的View区别
    -传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
    -视图方法可以返回REST framework的Response对象-
    -任何APIException异常都会被捕获到,并且处理成合适的响应信息;
    -在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制
    
    
# 两个视图基类
	APIVIew
    	-类属性:
            renderer_classes # 响应格式
    		parser_classes #能够解析的请求格式
    		authentication_classes#认证类
    		throttle_classes#频率类
    		permission_classes#权限类
    	-基于APIView+ModelSerializer+Resposne写5个接口
        	-详见代码

5.1 APIView+ModelSerializer+Resposne写5个接口

5.1.1 视图类

from .models import Book
from .serializer import BookSerializer


class BookView(APIView):
    def get(self, request):
        books = Book.objects.all()
        ser = BookSerializer(instance=books, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            # 咱们现在只有ser序列化类的对象,但是咱们想要,新增的对象---》序列化成字典---》大前提,序列化类中的create方法一定要返回新增的对象
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})


class BookDetailView(APIView):
    def get(self, request, pk):
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books)
        return Response(ser.data)

    def put(self, request, pk):
        books = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=books, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})

5.1.2 序列化类

### ModelSerializer的使用
class BookSerializer(serializers.ModelSerializer):
    # 跟表有关联
    class Meta:
        model = Book
        fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
        extra_kwargs = {'name': {'max_length': 8},
                        'publish_detail': {'read_only': True},
                        'author_list': {'read_only': True},
                        'publish': {'write_only': True},
                        'authors': {'write_only': True},
                        }

5.1.3 路由

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetailView.as_view()),
]

6 基于GenericAPIView+5个视图扩展类

6.1 视图类

from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
    ListModelMixin


# 基于GenericAPIView+5个视图扩展类写接口

class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        return self.create(request)


class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

6.2 视图类

class BookSerializer(serializers.ModelSerializer):
    # 跟表有关联
    class Meta:
        model = Book
        fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
        extra_kwargs = {'name': {'max_length': 8},
                        'publish_detail': {'read_only': True},
                        'author_list': {'read_only': True},
                        'publish': {'write_only': True},
                        'authors': {'write_only': True},
                        }

6.3 路由

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetailView.as_view()),
]

标签:self,request,视图,序列化,data,drf
From: https://www.cnblogs.com/super-xz/p/17093839.html

相关文章