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.\n'
                '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中定义的字段了

上一篇:matplotlib--文字图例


下一篇:11高阶函数作业