drf之反序列化校验源码分析 、 断言 、drf之请求和响应
一、反序列化校验源码分析
序列化类的校验功能
-局部钩子:必须 validate_字段名
-全局钩子: validate
入口:
-ser.is_valid 才做的校验---》入口
-BookSerializer---》Serializer——-》BaseSerializer---》is_valid---》继承了Field
-is_valid 方法
先来到BaseSerializer类中找到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判断+抛异常断定某个东西是我认为的,如果不是就抛异常
等同于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之请求
视图类:APIView
序列化组件:Serializer,ModelSerializer
drf:Request类的对象
drf:Response
3.1 Request类对象的分析
.data
request.data 返回解析之后的请求体数据。类似于Django中标准的request.POST和 request.FILES属性,但提供如下特性:
包含了解析之后的文件和非文件数据
包含了对POST、PUT、PATCH请求方式解析后的数据
利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
.query_params
request.query_params与Django标准的request.GET相同,只是更换了更正确的名称而
其他的属性用起来跟之前一样
3.2 请求,能够接受的编码格式
urlencoded
form-data
json
三种都支持
限制只能接受某种或某几种编码格式
限制方式一:在视图类上写---》只是局部视图类有效
# 总共有三个:JSONParser, FormParser, MultiPartParser
class BookView(APIView):
parser_classes = [JSONParser, FormParser]
限制方式二:在配置文件中写---》全局有效
# drf的配置,统一写成它
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
# 'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
全局配置了只支持json,局部想支持3个
-只需要在局部,视图类中,写3个即可
class BookView(APIView):
parser_classes = [JSONParser, FormParser,MultiPartParser]
总结:能够处理的请求方式编码
-优先从视图类中找
-再去项目配置文件找
-再去drf默认的配置中找
四、drf之响应
4.1 响应类的对象Response
return Response({code:100})
data:
响应体的内容,可以字符串,字典,列表
status:
http响应状态码
drf把所有响应码都定义成了一个常量
template_name:
模板名字,用浏览器访问,看到好看的页面,
-自定制页面
-根本不用
用postman访问,返回正常数据
headers:
响应头加数据(后面讲跨域问题再讲)
-headers={'name':'lqz'}
content_type:
响应编码,一般不用
三个重要的:data,status,headers
4.2 响应的格式
默认是两种:纯json,浏览器看到的样子
限制方式一:在视图类上写---》只是局部视图类有效
# 总共有两个个:JSONRenderer,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个
-只需要在局部,视图类中,写2个即可
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookView(APIView):
renderer_classes = [JSONRenderer,BrowsableAPIRenderer]