DRF ~ day05 之 反序列化校验源码分析、 断言、drf之请求、drf之响应、视图之两个视图基类

DRF之 反序列化校验源码分析、 断言、drf之请求、drf之响应、视图之两个视图基类



一、反序列化校验源码分析

# 序列化类的校验功能
	-局部钩子:必须    validate_字段名
    -全局钩子: validate
    
    
# 入口:
	-ser.is_valid 才做的校验---》入口
    -BookSerializer---》Serializer——-》BaseSerializer---》is_valid---》继承了Field
    -is_valid 方法
        def is_valid(self, *, raise_exception=False):
            # self中没有_validated_data,只有执行完后,才有
            if not hasattr(self, '_validated_data'):
                try:
                    # 核心---》这一句
                    # 想看它的源代码,按住ctrl+鼠标点击是不对的---》只能找当前类的父类
                    #但它真正的执行是,从根上开始找
                    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.run_validation(self.initial_data),不能按住ctrl+鼠标点点击,要从根上开始找
    -Serializer的run_validation
        def run_validation(self, data=empty):
             # 局部钩子
            value = self.to_internal_value(data)
            try:
                # 全局钩子
                value = self.validate(value) # BookSerializer只要写了,优先执行它的
            except (ValidationError, DjangoValidationError) as exc:
                raise ValidationError(detail=as_serializer_error(exc))

            return value
    
    -self.to_internal_value(data)---》Serializer类的方法
        def to_internal_value(self, data):
            for field in fields: #序列化类中写的一个个的字段类的对象列表
                # 一个field是name对象,field.field_name字符串 name
                # self是谁的对象:序列化类的对象,BookSerializer的对象  validate_name
                validate_method = getattr(self, 'validate_' + field.field_name, None)
                try:
                    # 字段自己的校验规则
                    validated_value = field.run_validation(primitive_value)
                    if validate_method is not None:
                        # 局部钩子
                        validated_value = validate_method(validated_value)
                except ValidationError as exc:
                    errors[field.field_name] = exc.detail
                except DjangoValidationError as exc:
                    errors[field.field_name] = get_error_detail(exc)
                except SkipField:
                    pass
                else:
                    set_value(ret, field.source_attrs, validated_value)

            if errors:
                raise ValidationError(errors)

            return ret
    
    
# 总结:
	-ser.is_valid---》走局部钩子的代码---》是通过反射获取BookSerializer中写的局部钩子函数,如果写了,就会执行----》走全局钩子代码---》self.validate(value)--->只要序列化类中写了,优先走自己的
    

二、 断言

# 断言
assert hasattr(self, 'initial_data'), (
            'Cannot call `.is_valid()` as no `data=` keyword argument was '
            'passed when instantiating the serializer instance.'
        )


# 断定某个东西是我认为的,如果不是就抛异常
# 等同于if判断+抛异常
def add(a, b):
    return a + b

res = add(8, 9)
# assert res == 16, Exception('不等于16')
if not res==16:
    raise Exception('不等于16')
print('随便')

三、drf之请求(请求类Request)

3.1 Request

REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。

REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。

Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。

无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。

3.2、request对象的属性

'''
1).data
    request.data 返回解析之后的请求体数据。类似于Django中标准的request.POST和 request.FILES属性,但提供如下特性:
    包含了解析之后的文件和非文件数据
    包含了对POST、PUT、PATCH请求方式解析后的数据
    利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
2).query_params
	request.query_params与Django标准的request.GET相同,只是更换了更正确的名称而
3) 其他的属性用起来跟之前一样
'''

3.3、request请求能够接受的编码格式

  • 支持的编码格式
'''
# urlencoded
# form-data
# json
三种都支持
限制只能接受某种或某几种编码格式
'''
  • 限制格式的方式

局部限制

# 限制方式一:在视图类上写---》只是局部视图类有效
	# 总共有三个:JSONParser, FormParser, MultiPartParser
	class BookView(APIView):
    	parser_classes = [JSONParser, FormParser]

全局限制

# 限制方式二:在配置文件中写---》全局有效
    # drf的配置,统一写成它
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',    # json格式
            # 'rest_framework.parsers.FormParser',   # form-data 格式
            # 'rest_framework.parsers.MultiPartParser',   # urlencoded 格式
        ],
    }

全局配置了只支持json,局部想支持3个

# 全局配置了只支持json,局部想支持3个
	-只需要在局部,视图类中,写3个即可
    class BookView(APIView):
    	parser_classes = [JSONParser, FormParser,MultiPartParser]

总结:

 # 总结:能够处理的请求方式编码
	-优先从视图类中找
    -再去项目配置文件找
    -再去drf默认的配置中找

四、drf之响应(响应类Response)

4.1、Response

rest_framework.response.Response

REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。

REST framework提供了Renderer 渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。

可以在rest_framework.settings查找所有的drf默认配置项

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
    )
}

4.2、Response(响应类)对象的属性

Response(data, status=None, template_name=None, headers=None, content_type=None)

# 源代码内容
class Response(SimpleTemplateResponse):
    """
    An HttpResponse that allows its data to be rendered into
    arbitrary media types.
    """

    def __init__(self, data=None, status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None):
        """
        Alters the init arguments slightly.
        For example, drop 'template_name', and instead use 'data'.

        Setting 'renderer' and 'media_type' will typically be deferred,
        For example being set automatically by the `APIView`.
        """
        super().__init__(None, status=status)

        if isinstance(data, Serializer):
            msg = (
                'You passed a Serializer instance as data, but '
                'probably meant to pass serialized `.data` or '
                '`.error`. representation.'
            )
            raise AssertionError(msg)

        self.data = data
        self.template_name = template_name
        self.exception = exception
        self.content_type = content_type

        if headers:
            for name, value in headers.items():
                self[name] = value






# Response 相应类的属性说明:
'''
# return Response({code:100})
-data:响应体的内容,可以字符串,字典,列表
-status:http响应状态码  
	-drf把所有响应码都定义成了一个常量

# 在配置文件中的app应用的对方添加才能使用浏览器访问
template_name:模板名字,用浏览器访问,看到好看的页面,用postman访问,返回正常数据
	-自定制页面
    -根本不用
headers:响应头加数据(后面讲跨域问题再讲)
	-headers={'name':'lqz'}
content_type:响应编码,一般不用


# 三个重要的:data,status,headers
'''

4.3、Response(响应类)响应的格式

默认是两种:纯json和浏览器看到的样子,设置无论谁访问都是纯json格式

  • 限制格式的方式

局部配置

# 限制方式一:在视图类上写---》只是局部视图类有效
	# 总共有两个个:JSONRenderer,BrowsableAPIRenderer
	# JSONRenderer  : json的
	# BrowsableAPIRenderer  : 浏览器得到
	from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
    class BookView(APIView):
        renderer_classes = [JSONRenderer]

全局配置

# 限制方式二:在配置文件中写---》全局有效
    # drf的配置,统一写成它
     REST_FRAMEWORK = {
        'DEFAULT_RENDERER_CLASSES': [
            'rest_framework.renderers.JSONRenderer',
            # 'rest_framework.renderers.BrowsableAPIRenderer',
        ],
    }

全局配置了只支持json,局部想支持2个

# 全局配置了只支持json,局部想支持2个
	-只需要在局部,视图类中,写2个即可
	from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
    class BookView(APIView):
        renderer_classes = [JSONRenderer,BrowsableAPIRenderer]
        

五、物理外键和逻辑外键

模型层

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)

    # on_delete:
    # CASCADE:级联删除,只要删除publish,跟publish关联的book,全都被删除
    # SET_DEFAULT:只要删除publish,跟publish关联的book,的publish字段会变成默认值,一定要配合default使用
    # SET_NULL:只要删除publish,跟publish关联的book,的publish字段会变成空,一定要配合null=True使用
    # models.SET(add):括号中可以放个值,也可以放个函数内存地址,只要删除publish,跟publish关联的book,的publish字段会变成set设的值或执行函数
    # models.DO_NOTHING:什么都不做,但它需要跟db_constraint=False配合,表示不建立外键约束,创建逻辑外键,不是物理外键
    # 不建立物理外键的好处?增删查改数据快
    #缺点:容易出现脏数据
    # 实际工作中,都不建立物理外键,都是建立逻辑外键
    publish = models.ForeignKey(to='Publish', on_delete=models.DO_NOTHING, null=True,db_constraint=False)
    authors = models.ManyToManyField(to='Author')


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)

六、两个视图基类

视图基类

# 视图层的类需要继承的基类
'''
# 视图类:
	-APIView:
	-GenericAPIView:GenericAPIView继承了APIView
'''
  • 继承APIView写接口
# # 1 继承APIView+序列化类+Resonse写5个接口
from rest_framework.views import APIView
from app01 import models
from app01.serializer import BookSerialzier


class BookView(APIView):
    def get(self, request):
        qs = models.Book.objects.all()
        ser = BookSerialzier(instance=qs, many=True)
        return Response({'code': 100, 'msg': '成功', 'results': ser.data})

    def post(self, request):
        ser = BookSerialzier(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})


class BookViews(APIView):
    def get(self, request, pk):
        ret = models.Book.objects.filter(pk=pk).first()
        ser = BookSerialzier(ret)
        return Response({'code': 100, 'msg': '成功', 'results': ser.data})

    def put(self, request, pk):
        ret = models.Book.objects.filter(pk=pk).first()
        ser = BookSerialzier(data=request.data, instance=ret)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '更新成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})
  • 继承GenericAPIView写接口
# 2 继承GenericAPIView+序列化类+Resonse写5个接口
from app01 import models
from rest_framework.response import Response
from app01.serializer import BookSerialzier
from rest_framework.generics import GenericAPIView


class BookView(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerialzier

    def get(self, request):
        qs = self.get_queryset()  # 相当于查询数据表的所有数据
        ser = self.get_serializer(qs, many=True)  # 相当于序列化类
        return Response({'code': 100, 'msg': '成功', 'results': ser.data})

    def post(self, request):
        ser = self.get_serializer(data=request.data)  # # 相当于序列化类
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})


class BookViews(GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerialzier

    def get(self, request, pk):
        book = self.get_object()
        ser = self.get_serializer(book)   # # 相当于序列化类
        return Response({'code': 100, 'msg': '成功', 'results': ser.data})

    def put(self, request, pk):
        book = self.get_object()  # 根据id查询所有数据
        ser = self.get_serializer(data=request.data, instance=book)  # 相当于序列化类
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '更新成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})

6.1、GenericAPIView的总结

# GenericAPIView
	-类属性:
    	queryset:要序列化的所有数据
    	serializer_class:序列化类
        lookup_field = 'pk' :查询单条时的key值
     -方法:
    	-get_queryset():获取所有要序列化的数据【后期可以重写】
        -get_serializer  : 返回序列化类
        -get_object :获取单个对象
        
        
        
 #总结:以后继承GenericAPIView写接口
	1 必须配置类属性
    	queryset
        serializer_class
     2 想获取要序列化的所有数据
    	get_queryset()
     3 想使用序列化类:
    	get_serializer
     4 想拿单条
    	get_object

总结

以上就是今天要讲的内容,本文仅仅简单介绍了 反序列化、drf的请求和响应、两个视图基类 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值