反序列化数据校验,
校验顺序为:先校验字段自己的规则(最大、最小),然后是局部钩子,然后是全局钩子
反序列化校验开始
在视图类中的s_valid()
被执行时,就会进行反序列化的校验,校验通过返回True
,否则返回False
反序列化的过程
BaseSerializer类
def is_valid(self, *, raise_exception=False):
'断言检查,确保类的实例中具有名为initial_data的属性,如果没有就引发下面这段话包含的特定的错误信息'
assert hasattr(self, 'initial_data'), (
'Cannot call `.is_valid()` as no `data=` keyword argument was '
'passed when instantiating the serializer instance.'
)
if not hasattr(self, '_validated_data'):
'''
self序列化类的对象,属性中没有_validated_data,就一定会走这句
并且只要走过一次后,下一次就无需再次走了,它优化了is_valid被多次调用,只会走一次校验
'''
try:
'真正的走校验,一旦执行了这里,以后self中就有了_validated_data'
'''
然后我们就得去看看这个self.run_validation(self.initial_data)
我们不能直接按住ctrl键点击,因为它会从当前类中找run_validation,
我们得清楚,这个self是谁,它还是我们的视图类,所以我们得返回到视图类从它一步一步往它继承的类中找
清楚如何查找后,我们就从视图类----》serializer.Serializer(找到了,为什么从这个里面找因为
我们就是使用serializer.Serializer类的)
'''
self._validated_data = self.run_validation(self.initial_data)
'''
这下面的是当校验不通过时,执行的,会给_validatad_data设置为一个空字段,
并且给_errors设置为验证错误的详细信息
'''
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {}
return not bool(self._errors)
通过上面self.run_validation(self.initial_data)我们找到了下面这块源码,
而这里的run_validatiion方法就是DRF序列化器验证过程中的核心
def run_validation(self, data=empty):
'''
局部钩子的执行,这里的self就还是视图类的对象
data就是前端传入的数据,value是前端传入,字段自己校验通过的字典
'''
value = self.to_internal_value(data)
try:
'这个是字段验证器'
self.run_validators(value)
'''
这个是全局钩子的执行,和上面一样self是视图类的对象,如果我们在序列化其中写了全局钩子,
那么就优先使用我们自己定义的全局钩子,如果没写则执行父类的,(serializer.Serializer)
结果可以看到父类根本就没有做校验
def validate(self, attrs):
return attrs
'''
value = self.validate(value) #运行自定义验证方法
'确保自定义验证方法返回了验证后的数据'
assert value is not None, '.validate() should return the validated data'
except (ValidationError, DjangoValidationError) as exc:
# 捕获验证过程中可能引发的异常,并转换为DRF的ValidationError
raise ValidationError(detail=as_serializer_error(exc))
# 返回验证后的数据
return value
看完了全局钩子后我们在看一下局部钩子的self.to_internal_value(data),也是一样的思路,从视图类找,
视图类肯定没有,然后找父类serializer结果就是这个页面的
def to_internal_value(self, data):
ret = OrderedDict()# 用于存储验证后的数据
errors = OrderedDict()# 用于存储字段验证过程中的错误信息
fields = self._writable_fields# 获取序列化器中的所有字段
'序列化类中所有的字段,for循环每次取一个字段对象。例如name=CharField()'
for field in fields:
'''去视图类的对象中反射,validate_字段名的方法,如果有就执行,没有就不执行'''
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
'这句话就是字段自己的校验规则(最长最短长度等)'
validated_value = field.run_validation(primitive_value)
'局部钩子,如果在序列化类中写了局部钩子验证规则,就运行自己写的'
if validate_method is not None:
'执行局部钩子,传入当前字段的value值'
validated_value = validate_method(validated_value)
'如果抛异常了就会被捕获'
except ValidationError as exc:
'捕获DRF的ValidationError异常'
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
'捕获Django的ValidationError异常'
errors[field.field_name] = get_error_detail(exc)
except SkipField:
'如果遇到SkipField异常,就跳过该字段的处理'
pass
else:
'如果没有异常,将验证后的值设置到结果中'
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
'''普通写法'''
name = 'jack1'
if not name == 'jack':
raise Exception('name不登录jack')
'''断言写法'''
'assert 后写条件,只要不符合条件,就会跑AssertionErro异常,后面写异常信息'
name = 'tom'
assert name == 'tom','name不是tom'
print('程序执行完毕!')
'源码中使用'
assert value is not None, '.validate() should return the validated data'
Request类
REST FrameWork传入视图的Request对象不再是Django默认的HttpRequest对象
而是REST FrameWork提供的扩展了HttpResponse类的Request类的对象了
Rest FrameWork提供了Parser
解析器 在接收到请求后自动根据Content-type
指明的数据类型(默认是JSON)
将请求数据进行Parse解析 解析为字典[QueryDict]
对象保存到Request对象
中
Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果
无论前端发送的哪种格式数据 我们都可以用同一个一种方式读取数据
属性data
request.data
返回解析之后的请求题数据 类似于Django中的request.POST
和request.FILES
属性
属性query_params
request.query_params
与Django标准的request.GET
相同 只是更换了更正确的名称
Response类
Response(data=None, status=None,template_name=None, headers=None,exception=False, content_type=None)
REST FrameFork提供了一个响应类Response
使用该类构造响应对象时 响应的具体数据内容会被转换(render渲染)成符合前端需求的类型
REST FrameFork提供了Renderer
渲染器 用来根据请求投中的Accept接收数据类型声明 来自动转换响应数据到对应格式 如果前端请求中未进行Accept声明 则会采用默认方式处理响应数据
我们可以通过配置来修改默认响应格式 可以在rest_framework.settings
查找所有的drf默认配置项
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类
'rest_framework.renderers.JSONRenderer', # JSON渲染器
'rest_framework.renderers.BrowsableAPIRenderer', # 浏览器API渲染器
)
}
参数说明:
常用属性
状态码
为了方便设置状态码,REST framewrok在rest_framework.status模块中提供了常用状态码常量。
1)信息告知 - 1xx
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
2)成功 - 2xx
HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS
3)重定向 - 3xx
HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
4)客户端错误 - 4xx
HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
5)服务器错误 - 5xx
HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
方式一
局部配置
在继承APIView及其子类的的视图类中配置
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
class BookView(APIView):
parser_classes = [JSONParser,]
方式二
全局配置
在配置文件中配置(影响所有,全局配置)
from django.conf import settings
from djangoday01 import settings
from rest_framework import settings
from drf_day05 import settings
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser', # 默认json默认
'rest_framework.parsers.FormParser', # 默认urlencoded编码
'rest_framework.parsers.MultiPartParser', # 默认form_data编码
],
}
方式三
如果全局配了1个,某个视图类想要3个,如何配置?
方式一
在视图类中写-----局部配置
# 响应格式
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookView(APIView):
renderer_classes=[JSONRenderer,]
方式二
在项目配置文件中写—全局配置
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
}
方式三
使用顺序(一般就用内置的即可)。使用顺序:视图类自身配置——>项目drf配置——>drf默认内置的配置
urls.py
我这里使用了路由分发,include
'总路由'
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('app01.urls')),
]
'子路由app01/urls.py'
from django.urls import path
from . import views
urlpatterns = [
path('books/',views.BookView.as_view()),
path('books/' ,views.BookDetailView.as_view()),
]
序列化类serializer.py
from . import models
from rest_framework import serializers
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ['name', 'price', 'publish', 'authors', 'publish_detail', 'author_list']
extra_kwargs = {
'publish': {'write_only': True}, 反序列化
'authors': {'write_only': True}, 反序列化
'publish_detail': {'read_only': True}, 序列化
'author_list': {'read_only': True}, 序列化
}
视图层views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializer import BookSerializer
from . import models
class BookView(APIView):
def get(self, request): # 获取多条数据
book = models.Book.objects.all()
'''instance表示要序列化的数据,many=True表示序列化多条(instance是QuerySet对象)'''
ser = BookSerializer(instance=book, many=True)# 序列化多条需要many=True
return Response(ser.data)
def post(self, request):
ser = BookSerializer(data=request.data) # 从前端传递数据从request.data中取出来
if ser.is_valid(): # is_valid表示校验前端传入的数据,但是我们没有写校验规则
'保存,因为我序列化类继承的是ModelSerializer类所以无需重写create方法'
ser.save() # 调用ser.save,自动触发自定义编辑create方法保存数据
return Response(ser.data)
else:
return Response(ser.errors)
class BookDetailView(APIView):
def get(self, request, pk): # 获取单条数据
book = models.Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
book = models.Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
def delete(self, request, pk):
models.Book.objects.filter(pk=pk).delete()
return Response('')
路由和序列化类内容跟上面一样,无需变动
继承GenericAPIView的写法
1.在类中,写两个类属性(所有属性、序列化类)
queryset = models.Book.object.all()
serializer_class = BookSerializer
2.获取所有要序列化的数据
self.get_queryset()
3.获取序列化类
self.get_serializer()
4.获取单条数据
self.get_object()
视图层views.py
from rest_framework.generics import GenericAPIView
class BookView(GenericAPIView):
'配置两个类属性'
queryset = models.Book.objects.all()
serializer_class = BookSerializer
def get(self, request):
obj_list = self.get_queryset() # 获取所有要序列化的数据
ser = self.get_serializer(instance=obj_list, many=True)# 获取序列化类
return Response(ser.data)
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
class BookDetailView(GenericAPIView):
queryset = models.Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
obj = self.get_object()
ser = self.get_serializer(instance=obj)
return Response(ser.data)
def put(self, request, *args, **kwargs):
obj = self.get_object()# 获取单挑---》内部就是按pk从request中取,取出pk对应的值,查询的
ser = self.get_serializer(instance=obj, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
def delete(self, request, *args, **kwargs):
self.get_object().delete()
return Response('')