ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

django rest framework序列化过程剖析

2021-04-06 17:36:24  阅读:223  来源: 互联网

标签:get self rest django kwargs 序列化 data class serializer


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中定义的字段了

标签:get,self,rest,django,kwargs,序列化,data,class,serializer
来源: https://www.cnblogs.com/arrow-kejin/p/14622737.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有