• django rest framework序列化过程剖析


    class AbcViewset(ModelViewSet):
        permission_classes = (IsAuthenticated,)
        pagination_class = MaxSizePagination
        authentication_classes = (JSONWebTokenAuthentication, authentication.SessionAuthentication)
        def get_serializer_class(self):
            if self.action == "retrieve":
                return AbcSerializer
            elif self.action == "create":
                return AbcSerializer
    
            return AbcSerializer
    class AbcSerializer(serializers.ModelSerializer):
        class Meta:
            model = AbcModel
            fields = "__all__"

    在一个继承了`from rest_framework.viewsets.ModelViewSet`类的视图中,当使用list方法返回格式化数据的时候实际上是调用的`from rest_framework.mixins.ListModelMixin`类的list方法

    当然retrieve方法返回数据调用的就是`from rest_framework.mixins.RetrieveModelMixin`类的retrieve,在这个方法中就会使用到`get_serializer`方法(action可以有增删改查和单独查的5个类别)

    class RetrieveModelMixin:
        """
        Retrieve a model instance.
        """
        def retrieve(self, request, *args, **kwargs):
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)
    
    class ListModelMixin:
        """
        List a queryset.
        """
        def list(self, request, *args, **kwargs):
            queryset = self.filter_queryset(self.get_queryset())
    
            page = self.paginate_queryset(queryset)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)

    这里get_serializer方法在from rest_framework.generics.GenericAPIView类中定义,在其中会调用到get_serializer_class方法在获取视图中定义的serializer类,由此开始了序列化的类的导入

    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__
        )
    
        return self.serializer_class

    serializer类的继承关系是AbcSerializer -- rest_framework.serializers.ModelSerializer -- rest_framework.serializers.Serializer -- rest_framework.serializers.BaseSerializer

    rest_framework.serializers.ListSerializer类也是继承的rest_framework.serializers.BaseSerializer类

    在对serializer类做初始化的时候会执行rest_framework.serializers.BaseSerializer类的__new__和__init__(因为序列化类是继承的BaseSerializer类)

        def __init__(self, instance=None, data=empty, **kwargs):
            self.instance = instance
            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.
            if kwargs.pop('many', False):
                return cls.many_init(*args, **kwargs)
            return super().__new__(cls, *args, **kwargs)
    
        @classmethod
        def many_init(cls, *args, **kwargs):
            """
            This method implements the creation of a `ListSerializer` parent
            class when `many=True` is used. You can customize it if you need to
            control which keyword arguments are passed to the parent, and
            which are passed to the child.
    
            Note that we're over-cautious in passing most arguments to both parent
            and child classes in order to try to cover the general case. If you're
            overriding this method you'll probably want something much simpler, eg:
    
            @classmethod
            def many_init(cls, *args, **kwargs):
                kwargs['child'] = cls()
                return CustomListSerializer(*args, **kwargs)
            """
            allow_empty = kwargs.pop('allow_empty', None)
            child_serializer = cls(*args, **kwargs)
            list_kwargs = {
                'child': child_serializer,
            }
            if allow_empty is not None:
                list_kwargs['allow_empty'] = allow_empty
            list_kwargs.update({
                key: value for key, value in kwargs.items()
                if key in LIST_SERIALIZER_KWARGS
            })
            meta = getattr(cls, 'Meta', None)
            list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
            return list_serializer_class(*args, **list_kwargs)

    在这里对类的实例化的过程中会先调用__new__方法来看是需要导出数据集合还是单个数据(以many是不是为True来判断),如果为True将会执行many_init方法

    在这里将child绑定到类实例本身,并返回ListSerializer类(将要初始化的类是ListSerializer)

    class ListSerializer(BaseSerializer):
        child = None
        many = True
    
        def __init__(self, *args, **kwargs):
            self.child = kwargs.pop('child', copy.deepcopy(self.child))
            self.allow_empty = kwargs.pop('allow_empty', True)
            assert self.child is not None, '`child` is a required argument.'
            assert not inspect.isclass(self.child), '`child` has not been instantiated.'
            super().__init__(*args, **kwargs)
            self.child.bind(field_name='', parent=self)
        def to_representation(self, data):
            """
            List of object instances -> List of dicts of primitive datatypes.
            """
            # Dealing with nested relationships, data can be a Manager,
            # so, first get a queryset from the Manager if needed
            iterable = data.all() if isinstance(data, models.Manager) else data
    
            return [
                self.child.to_representation(item) for item in iterable
            ]
        @property
        def data(self):
            ret = super().data
            return ReturnList(ret, serializer=self)

    当使用.data属性获取数据的时候就会开始真正的序列化过程了,这里的data方法中调用了父类BaseSerializer的data方法

    @property
        def data(self):
            if hasattr(self, 'initial_data') and not hasattr(self, '_validated_data'):
                msg = (
                    'When a serializer is passed a `data` keyword argument you '
                    'must call `.is_valid()` before attempting to access the '
                    'serialized `.data` representation.
    '
                    'You should either call `.is_valid()` first, '
                    'or access `.initial_data` instead.'
                )
                raise AssertionError(msg)
    
            if not hasattr(self, '_data'):
                if self.instance is not None and not getattr(self, '_errors', None):
                    self._data = self.to_representation(self.instance)
                elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
                    self._data = self.to_representation(self.validated_data)
                else:
                    self._data = self.get_initial()
            return self._data

    注意了在BaseSerializer类的data方法中,如果是many为True的情况下是调用的是ListSerializer类的to_representation方法,在这里将会把集合中的每一个数据做序列化操作,如果不是many为True那么就是调用的rest_framework.serializers.Serializer类的to_representation

    方法(当然在ListSerializer类的to_representation方法中循环集合中的每个数据的时候也是调用rest_framework.serializers.Serializer类的to_representation方法)

    class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
         def to_representation(self, instance):
            """
            Object instance -> Dict of primitive datatypes.
            """
            ret = OrderedDict()
            fields = self._readable_fields
    
            for field in fields:
                try:
                    attribute = field.get_attribute(instance)
                except SkipField:
                    continue
    
                # We skip `to_representation` for `None` values so that fields do
                # not have to explicitly deal with that case.
                #
                # For related fields with `use_pk_only_optimization` we need to
                # resolve the pk value.
                check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
                if check_for_none is None:
                    ret[field.field_name] = None
                else:
                    ret[field.field_name] = field.to_representation(attribute)
    
            return ret

    在这里完成对数据的序列化,这里field就是我们在AbcSerializer中定义的字段了

  • 相关阅读:
    关于JSONP
    使用stylelint对CSS/Sass做代码审查
    关于input的file框onchange事件触发一次失效的新的解决方法
    HTML5 之 FileReader(图片上传)
    document.domain
    window.hostory(浏览器的历史记录)
    事件DOMContentLoaded和load的区别
    JavaScript中---作用域
    关于repaint(重绘)和reflow( 回流)
    bootstrap兼容性问题
  • 原文地址:https://www.cnblogs.com/arrow-kejin/p/14622737.html
Copyright © 2020-2023  润新知