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
上一篇下一篇

猜你喜欢

热点阅读