Django Rest Framework 源码解析--序列化之
2019-12-23 本文已影响0人
叶_叶
Django Rest Framework 源码解析--序列化之反序列化
示例代码就只展示了后端编写的代码和序列化过程,示例代码如下:
懒得分文件就全部写再views.py中了
import re
from django.db import models
from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
class UserProfile(models.Model):
"""
用户表
"""
username = models.CharField(
max_length=20, default="", verbose_name="姓名", help_text="姓名")
email = models.EmailField(
max_length=50, verbose_name="邮箱", help_text="邮箱")
class UserSerializer(serializers.ModelSerializer):
"""
用户序列化
"""
class Meta:
model = UserProfile
fields = "__all__"
class UserViewSet(ModelViewSet):
"""
用户管理:增删改查
"""
queryset = UserProfile.objects.all()
serializer_class = UserSerializer
url.py
from django.contrib import admin
from django.urls import path, include
from study.views import UserViewSet
from rest_framework import routers
router = routers.SimpleRouter()
router.register(r"users", UserViewSet, base_name="users")
urlpatterns = [
path('admin/', admin.site.urls),
path(r"api/", include(router.urls))
一、新增用户Serializer的序列化过程
1、获取序列化对象
class CreateModelMixin:
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
# 序列化对象
# 这里面的传参要说明一点data有值就是反序列化,instance有值就是序列化
# 新增数据这里就是反序列化
serializer = self.get_serializer(data=request.data)
# 效验数据
serializer.is_valid(raise_exception=True)
# 执行创建
self.perform_create(serializer)
"""
def perform_create(self, serializer):
serializer.save()
"""
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
class GenericAPIView(views.APIView):
.......
serializer_class = None
.......
def get_serializer(self, *args, **kwargs):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
# 获取序列化对象
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_serializer_class(self):
"""
Return the class to use for the serializer.
Defaults to using `self.serializer_class`.
You may want to override this if you need to provide different
serializations depending on the incoming request.
(Eg. admins get full serialization, others get basic serialization)
"""
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
# 返回的就是我们再Views定义的serializer_class = UserSerializer
return self.serializer_class
......
通过上一步我们了解到serializer = self.get_serializer(data=request.data) 执行的UserSerializer类的实例化,并传入data参数执行反序列化
2、UserSerializer类的实例化的过程
类实例化之前会执行new方法,用于控制一个类的生成实例的过程生成一个空对象,子类没有的就去找父类的new, new 执行完以后才能执行init构造方法
UserSerializer的父类ModelSerializer没有new方法,ModelSerializer的父类Serializer也没有new方法,在往上找BaseSerlizer中的new方法
class BaseSerializer(Field):
.......
def __init__(self, instance=None, data=empty, **kwargs):
self.instance = instance
# 传入的data参数赋值给了self.initial_data
if data is not empty:
self.initial_data = data
self.partial = kwargs.pop('partial', False)
self._context = kwargs.pop('context', {})
kwargs.pop('many', None)
super().__init__(**kwargs)
def __new__(cls, *args, **kwargs):
# We override this method in order to automagically create
# `ListSerializer` classes instead when `many=True` is set.
# many参数默认为False, 所以这次初始化不走下面的many_init
if kwargs.pop('many', False):
return cls.many_init(*args, **kwargs)
# 执行父类Field的new
return super().__new__(cls, *args, **kwargs)
3、UserSerializer类的实例化后执行serializer.is_valid(raise_exception=True)方法验证数据
class BaseSerializer(Field):
......
def is_valid(self, raise_exception=False):
assert not hasattr(self, 'restore_object'), (
'Serializer `%s.%s` has old-style version 2 `.restore_object()` '
'that is no longer compatible with REST framework 3. '
'Use the new-style `.create()` and `.update()` methods instead.' %
(self.__class__.__module__, self.__class__.__name__)
)
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'):
try:
# 核心代码 运行验证self.initial_data数据
# 上面也提到了我们传入的data数据经过序列化后赋值给了self.initial_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)
# 重新了父父类Field的run_validation方法
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
......
def run_validation(self, data=empty):
"""
We override the default `run_validation`, because the validation
performed by validators and the `.validate()` method should
be coerced into an error dictionary with a 'non_fields_error' key.
"""
# 验证空值
(is_empty_value, data) = self.validate_empty_values(data)
# 是空值返回data
if is_empty_value:
return data
# 局部钩子验证 返回OrderedDict()实例化对象
value = self.to_internal_value(data)
try:
# 运行验证器
self.run_validators(value)
# 全局钩子验证
value = self.validate(value)
"""
这里的全局钩子如果我们需要使用的时候,需要重写,重写的时候一定要返回被拿出来验证的属性
def validate(self, attrs):
return attrs
"""
assert value is not None, '.validate() should return the validated data'
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
# self.validate_empty_values 验证空值
class Field:
......
def get_default(self):
"""
如果没有为该字段提供输入,则返回验证数据时使用的默认值。
如果这个字段还没有设置默认值,那么它只会引发“SkipField”,这表明不应该在这个字段的验证数据中设置任何值。
"""
if self.default is empty or getattr(self.root, 'partial', False):
# No default, or this is a partial update.
raise SkipField()
if callable(self.default):
if hasattr(self.default, 'set_context'):
self.default.set_context(self)
return self.default()
return self.default
def validate_empty_values(self, data):
"""
# 验证空值,或者:
# *Raise “ValidationError”,表示数据无效。
# *Raise “SkipField”,表示该字段应该被忽略。
# * Return (True, data),表示一个空值,应该在不应用任何进一步验证的情况下返回。
# *Return (False, data),指示一个非空值,该值应该正常应用验证。
"""
# self.get_default() 获取默认值
# 如果有只读权限
if self.read_only:
return (True, self.get_default())
if data is empty:
# 判断是否是部分更新
if getattr(self.root, 'partial', False):
raise SkipField()
# 判断是否必填
if self.required:
self.fail('required')
return (True, self.get_default())
if data is None:
# 是否允许为null类型
if not self.allow_null:
self.fail('null')
# 当指定的字段为空值时,不应该跳过可空的' source='*' '字段。这是因为' source='*' '意味着字段被传递给整个对象,而对象不是null。
elif self.source == '*':
return (False, None)
return (True, None)
return (False, data)
局部钩子验证self.to_internal_value(data)
# 重新了父父类Field的to_internal_value方法
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
......
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
if not isinstance(data, Mapping):
message = self.error_messages['invalid'].format(
datatype=type(data).__name__
)
raise ValidationError({
api_settings.NON_FIELD_ERRORS_KEY: [message]
}, code='invalid')
ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields
for field in fields:
# 如果反射获取方法赋值给validate_method
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
validated_value = field.run_validation(primitive_value)
# 如果存在局部钩子函数,则验证validated_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
4、数据验证之后执行的就是serializer.save()方法
class BaseSerializer(Field):
.......
def save(self, **kwargs):
assert not hasattr(self, 'save_object'), (
'Serializer `%s.%s` has old-style version 2 `.save_object()` '
'that is no longer compatible with REST framework 3. '
'Use the new-style `.create()` and `.update()` methods instead.' %
(self.__class__.__module__, self.__class__.__name__)
)
assert hasattr(self, '_errors'), (
'You must call `.is_valid()` before calling `.save()`.'
)
assert not self.errors, (
'You cannot call `.save()` on a serializer with invalid data.'
)
# Guard against incorrect use of `serializer.save(commit=False)`
assert 'commit' not in kwargs, (
"'commit' is not a valid keyword argument to the 'save()' method. "
"If you need to access data before committing to the database then "
"inspect 'serializer.validated_data' instead. "
"You can also pass additional keyword arguments to 'save()' if you "
"need to set extra attributes on the saved model instance. "
"For example: 'serializer.save(owner=request.user)'.'"
)
assert not hasattr(self, '_data'), (
"You cannot call `.save()` after accessing `serializer.data`."
"If you need to access data before committing to the database then "
"inspect 'serializer.validated_data' instead. "
)
validated_data = dict(
list(self.validated_data.items()) +
list(kwargs.items())
)
# 如果实例不为空执行的是更新,否则执行创建(这里是创建就不看update了)
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:
# 调用create方法
self.instance = self.create(validated_data)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
return self.instance
self.create(validated_data)
# 重写 BaseSerializer 中的create方法
class ModelSerializer(Serializer):
......
# Default `create` and `update` behavior...
def create(self, validated_data):
"""
We have a bit of extra checking around this in order to provide
descriptive messages when something goes wrong, but this method is
essentially just:
return ExampleModel.objects.create(**validated_data)
If there are many to many fields present on the instance then they
cannot be set until the model is instantiated, in which case the
implementation is like so:
example_relationship = validated_data.pop('example_relationship')
instance = ExampleModel.objects.create(**validated_data)
instance.example_relationship = example_relationship
return instance
The default implementation also does not handle nested relationships.
If you want to support writable nested relationships you'll need
to write an explicit `.create()` method.
"""
raise_errors_on_nested_writes('create', self, validated_data)
ModelClass = self.Meta.model
# Remove many-to-many relationships from validated_data.
# They are not valid arguments to the default `.create()` method,
# as they require that the instance has already been saved.
info = model_meta.get_field_info(ModelClass)
many_to_many = {}
for field_name, relation_info in info.relations.items():
if relation_info.to_many and (field_name in validated_data):
many_to_many[field_name] = validated_data.pop(field_name)
try:
instance = ModelClass._default_manager.create(**validated_data)
except TypeError:
tb = traceback.format_exc()
msg = (
'Got a `TypeError` when calling `%s.%s.create()`. '
'This may be because you have a writable field on the '
'serializer class that is not a valid argument to '
'`%s.%s.create()`. You may need to make the field '
'read-only, or override the %s.create() method to handle '
'this correctly.\nOriginal exception was:\n %s' %
(
ModelClass.__name__,
ModelClass._default_manager.name,
ModelClass.__name__,
ModelClass._default_manager.name,
self.__class__.__name__,
tb
)
)
raise TypeError(msg)
# Save many-to-many relationships after the instance is created.
if many_to_many:
for field_name, value in many_to_many.items():
field = getattr(instance, field_name)
field.set(value)
return instance