Django Rest Framework 源码解析--序列化

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 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)
        # 获取序列化对象
        # 这里面的传参要说明一点data有值就是反序列化,instance有值就是序列化
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
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(queryset, many=True) 执行的UserSerializer类的实例化

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
        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=True,执行cls.many_init(*args, **kwargs)
        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)
        # 调用ListSerializer
        list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
        return list_serializer_class(*args, **list_kwargs)
      # 后面就是执行各个类的init构造方法

3、UserSerializer类的实例化后执行return Response(serializer.data)

class ListSerializer(BaseSerializer):
    ......
    @property
    def data(self):
        # 执行父类的data
        ret = super().data
        return ReturnList(ret, serializer=self)
      
class BaseSerializer(Field):
    ......
    @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.'
            )
            # 如果要访问data属性必须先调用is_valid方法进行检查
            raise AssertionError(msg)
        # 如果没有_data属性
        if not hasattr(self, '_data'):
            # 实例不为空并且没有_errors属性
            if self.instance is not None and not getattr(self, '_errors', None):
                self._data = self.to_representation(self.instance)
            # 如果有is_valid后的数据并没有检查出错误则调用to_representation处理
            elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
                self._data = self.to_representation(self.validated_data)
            else:
                # 如果都不符合则调用get_initial处理
                self._data = self.get_initial()
        return self._data

4、由于我们传入的instance,在执行self.to_representation函数时,就传入了instance实例

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:
                # 获取实例中对应的field字段
                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:
                # 否则调用field的to_representation来处理attribute
                ret[field.field_name] = field.to_representation(attribute)

        return ret
@property
def _readable_fields(self):
    # 在初始化的时候就获取只读的字段值
    for field in self.fields.values():
        if not field.write_only:
            yield field
@cached_property
def fields(self):
    """
    A dictionary of {field_name: field_instance}.
    """
    # `fields` is evaluated lazily. We do this to ensure that we don't
    # have issues importing modules that use ModelSerializers as fields,
    # even if Django's app-loading stage has not yet run.
    fields = BindingDict(self)
    # 调用get_fields获取字段属性值
    for key, value in self.get_fields().items():
        # 写入该值
        fields[key] = value
    # 返回该字段
    return fields
class ModelSerializer(Serializer):
    ......
    def get_fields(self):
        """
        Return the dict of field names -> field instances that should be
        used for `self.fields` when instantiating the serializer.
        """
        # 检查url_field_name
        if self.url_field_name is None:
            self.url_field_name = api_settings.URL_FIELD_NAME
        # 必须配置Meta属性
        assert hasattr(self, 'Meta'), (
            'Class {serializer_class} missing "Meta" attribute'.format(
                serializer_class=self.__class__.__name__
            )
        )
        # 必须在Meta中配置model属性
        assert hasattr(self.Meta, 'model'), (
            'Class {serializer_class} missing "Meta.model" attribute'.format(
                serializer_class=self.__class__.__name__
            )
        )
        # 如果是抽象则直接报错
        if model_meta.is_abstract_model(self.Meta.model):
            raise ValueError(
                'Cannot use ModelSerializer with Abstract Models.'
            )
        # 深拷贝所有字段
        declared_fields = copy.deepcopy(self._declared_fields)
        # 获取model
        model = getattr(self.Meta, 'model')
        # 获取深度信息
        depth = getattr(self.Meta, 'depth', 0)
        # 深度必须大于等于0小于等于10
        if depth is not None:
            assert depth >= 0, "'depth' may not be negative."
            assert depth <= 10, "'depth' may not be greater than 10."

        # Retrieve metadata about fields & relationships on the model class.
        # 获取model的信息
        info = model_meta.get_field_info(model)
        # 获取filed字段名称
        field_names = self.get_field_names(declared_fields, info)

        # Determine any extra field arguments and hidden fields that
        # should be included
        # 获取额外参数
        extra_kwargs = self.get_extra_kwargs()
        extra_kwargs, hidden_fields = self.get_uniqueness_extra_kwargs(
            field_names, declared_fields, extra_kwargs
        )

        # Determine the fields that should be included on the serializer.
        fields = OrderedDict()
        # 遍历字段名称
        for field_name in field_names:
            # If the field is explicitly declared on the class then use that.
            # 如果在初始化的字段中
            if field_name in declared_fields:
                # 直接设置比进行下一个
                fields[field_name] = declared_fields[field_name]
                continue
                	
            # 获取额外定义的字段
            extra_field_kwargs = extra_kwargs.get(field_name, {})
            source = extra_field_kwargs.get('source', '*')
            if source == '*':
                source = field_name

            # Determine the serializer field class and keyword arguments.
            # 确定序列化器字段类和关键字参数
            field_class, field_kwargs = self.build_field(
                source, info, model, depth
            )

            # Include any kwargs defined in `Meta.extra_kwargs`
            field_kwargs = self.include_extra_kwargs(
                field_kwargs, extra_field_kwargs
            )

            # Create the serializer field.
            # 创建额外字段的field实例
            fields[field_name] = field_class(**field_kwargs)

        # Add in any hidden fields.
        fields.update(hidden_fields)

        return fields

此时就通过Model转换成了序列化中渲染的字段值,在获取属性的过程中,其中filed.get_attribute方法,其实就是调用了如下方法;

def get_attribute(instance, attrs):
    """
    Similar to Python's built in `getattr(instance, attr)`,
    but takes a list of nested attributes, instead of a single attribute.

    Also accepts either attribute lookup on objects or dictionary lookups.
    """
    # 遍历属性列表
    for attr in attrs:
        try:
            # 检查是否为Mapping
            if isinstance(instance, Mapping):
                # 直接获取属性
                instance = instance[attr]
            else:
                # 直接获取实例的该属性
                instance = getattr(instance, attr)
        except ObjectDoesNotExist:
            return None
        if is_simple_callable(instance):
            try:
                instance = instance()
            except (AttributeError, KeyError) as exc:
                # If we raised an Attribute or KeyError here it'd get treated
                # as an omitted field in `Field.get_attribute()`. Instead we
                # raise a ValueError to ensure the exception is not masked.
                raise ValueError('Exception raised in callable attribute "{}"; original exception was: {}'.format(attr, exc))

    return instance

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值