djangorestframework源码分析2:serializer序列化数据的执行流程
发布日期:2021-07-25 13:04:48 浏览次数:14 分类:技术文章

本文共 23936 字,大约阅读时间需要 79 分钟。

djangorestframework源码分析

本文环境python3.5.2,djangorestframework (3.5.1)系列

djangorestframework源码分析-serializer的执行流程

本次主要就是分析一下,djangorestframework中的序列化的工作的执行流程,主要是如果进行数据的序列化和返回的。本次示例代码就只展示了后端编写的代码和序列化过程,示例代码如下:

...from uuid import uuid4from django.db import modelsclass TestModel(models.Model):    uuid = models.UUIDField(primary_key=True, default=uuid4)    name = models.CharField(verbose_name="产品素材名称", max_length=200, null=True, blank=True)......from app_name.models import TestModelclass TestSerializer(serializers.ModelSerializer):    is_authorize = serializers.SerializerMethodField()    enterprise_name = serializers.SerializerMethodField()    enterprise_address = serializers.SerializerMethodField()    enterprise_name = serializers.CharField(        source='name')    class Meta:        model = TestModel        fields = ("uuid", "is_authorize", "enterprise_name", "enterprise_address", "name")    def get_enterprise_name(self, obj):        enterprise_name = obj.name        return enterprise_name    def get_is_authorize(self, obj):        return False    def get_enterprise_address(self, obj):        return "--"......from rest_framework.views import APIViewfrom app_name.models import TestModelfrom rest_framework.response import Responseclass TestAPI(APIView):    """ 测试api"""    view_name = 'unregister_company'    permission_classes = (IsAuthenticated, OperatorPermissions)    def get(self, requset, *args, **kwargs):        instance = TestModel.objects.first()        serializer = TestSerializer(instance)        return Response(serializer.data)...

其中代码包括了,TestModel、TestSerializer和TestAPI此时,就完成了对应的所有的后端代码,前端路由可自行配置。

Serializer的序列化过程

由于本例中使用了相对比较常见的serializers.ModelSerializer直接对django中的model实例进行序列化,所以先查看该类的定义:

class ModelSerializer(Serializer):                                      # 继承自Serializer    """    A `ModelSerializer` is just a regular `Serializer`, except that:    * A set of default fields are automatically populated.    * A set of default validators are automatically populated.    * Default `.create()` and `.update()` implementations are provided.    The process of automatically determining a set of serializer fields    based on the model fields is reasonably complex, but you almost certainly    don't need to dig into the implementation.    If the `ModelSerializer` class *doesn't* generate the set of fields that    you need you should either declare the extra/differing fields explicitly on    the serializer class, or simply use a `Serializer` class.    """    serializer_field_mapping = {        models.AutoField: IntegerField,        models.BigIntegerField: IntegerField,        models.BooleanField: BooleanField,        models.CharField: CharField,        models.CommaSeparatedIntegerField: CharField,        models.DateField: DateField,        models.DateTimeField: DateTimeField,        models.DecimalField: DecimalField,        models.EmailField: EmailField,        models.Field: ModelField,        models.FileField: FileField,        models.FloatField: FloatField,        models.ImageField: ImageField,        models.IntegerField: IntegerField,        models.NullBooleanField: NullBooleanField,        models.PositiveIntegerField: IntegerField,        models.PositiveSmallIntegerField: IntegerField,        models.SlugField: SlugField,        models.SmallIntegerField: IntegerField,        models.TextField: CharField,        models.TimeField: TimeField,        models.URLField: URLField,        models.GenericIPAddressField: IPAddressField,        models.FilePathField: FilePathField,    }                                                                           # django中的字段与restframework中字段的对应关系    if ModelDurationField is not None:        serializer_field_mapping[ModelDurationField] = DurationField    if ModelJSONField is not None:        serializer_field_mapping[ModelJSONField] = JSONField    serializer_related_field = PrimaryKeyRelatedField                           # 序列化时候的关联信息    serializer_related_to_field = SlugRelatedField    serializer_url_field = HyperlinkedIdentityField    serializer_choice_field = ChoiceField    # The field name for hyperlinked identity fields. Defaults to 'url'.    # You can modify this using the API setting.    #    # Note that if you instead need modify this on a per-serializer basis,    # you'll also need to ensure you update the `create` method on any generic    # views, to correctly handle the 'Location' response header for    # "HTTP 201 Created" responses.    url_field_name = None

从定义可知,ModelSerializer继承自Serializer,并且将django中的字段对应到了restframework中定义的字段,并且还定义了许多对于数据库中外键等关联关系的处理函数,由于此处没有讲述关于外键等场景故不详细分析有关数据库关系时的序列化过程,然后继续查看Serializer的定义:

@six.add_metaclass(SerializerMetaclass)class Serializer(BaseSerializer):    default_error_messages = {        'invalid': _('Invalid data. Expected a dictionary, but got {datatype}.')    }    @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.        if not hasattr(self, '_fields'):            self._fields = BindingDict(self) 					# 调用filed的bind方法 完成方法绑定            for key, value in self.get_fields().items():                self._fields[key] = value        return self._fields    ...class BaseSerializer(Field):    """    The BaseSerializer class provides a minimal class which may be used    for writing custom serializer implementations.    Note that we strongly restrict the ordering of operations/properties    that may be used on the serializer in order to enforce correct usage.    In particular, if a `data=` argument is passed then:    .is_valid() - Available.    .initial_data - Available.    .validated_data - Only available after calling `is_valid()`    .errors - Only available after calling `is_valid()`    .data - Only available after calling `is_valid()`    If a `data=` argument is not passed then:    .is_valid() - Not available.    .initial_data - Not available.    .validated_data - Not available.    .errors - Not available.    .data - Available.    """    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(BaseSerializer, self).__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(BaseSerializer, cls).__new__(cls, *args, **kwargs)    ...class Field(object):    _creation_counter = 0    default_error_messages = {        'required': _('This field is required.'),        'null': _('This field may not be null.')    }    default_validators = []    default_empty_html = empty    initial = None    def __init__(self, read_only=False, write_only=False,                 required=None, default=empty, initial=empty, source=None,                 label=None, help_text=None, style=None,                 error_messages=None, validators=None, allow_null=False):        self._creation_counter = Field._creation_counter        Field._creation_counter += 1        # If `required` is unset, then use `True` unless a default is provided.        if required is None:            required = default is empty and not read_only        # Some combinations of keyword arguments do not make sense.        assert not (read_only and write_only), NOT_READ_ONLY_WRITE_ONLY        assert not (read_only and required), NOT_READ_ONLY_REQUIRED        assert not (required and default is not empty), NOT_REQUIRED_DEFAULT        assert not (read_only and self.__class__ == Field), USE_READONLYFIELD        self.read_only = read_only        self.write_only = write_only        self.required = required        self.default = default        self.source = source        self.initial = self.initial if (initial is empty) else initial        self.label = label        self.help_text = help_text        self.style = {} if style is None else style        self.allow_null = allow_null        if self.default_empty_html is not empty:            if default is not empty:                self.default_empty_html = default        if validators is not None:            self.validators = validators[:]        # These are set up by `.bind()` when the field is added to a serializer.        self.field_name = None        self.parent = None        # Collect default error message from self and parent classes        messages = {}        for cls in reversed(self.__class__.__mro__):            messages.update(getattr(cls, 'default_error_messages', {}))        messages.update(error_messages or {})        self.error_messages = messages    ...

通过简单的定义可知,Serializer继承自BaseSerializer,BaseSerializer继承自Field,在Serializer在定义的时候还使用了SerializerMetaclass元类定义来操控属性;

class SerializerMetaclass(type):    """    This metaclass sets a dictionary named `_declared_fields` on the class.    Any instances of `Field` included as attributes on either the class    or on any of its superclasses will be include in the    `_declared_fields` dictionary.    """    @classmethod    def _get_declared_fields(cls, bases, attrs):        fields = [(field_name, attrs.pop(field_name))                  for field_name, obj in list(attrs.items())                  if isinstance(obj, Field)]                    # 检查属性是否是Field,如果是则从attrs中删除弹出        fields.sort(key=lambda x: x[1]._creation_counter)       # 重新排序        # If this class is subclassing another Serializer, add that Serializer's        # fields.  Note that we loop over the bases in *reverse*. This is necessary        # in order to maintain the correct order of fields.        for base in reversed(bases):                            # 排序基类            if hasattr(base, '_declared_fields'):                fields = list(base._declared_fields.items()) + fields       # 将所有父类的字段都相加        return OrderedDict(fields)    def __new__(cls, name, bases, attrs):        attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)              # 在创建类的时候添加属性_declared_fields        return super(SerializerMetaclass, cls).__new__(cls, name, bases, attrs)         # 生成类

梳理了大概的继承关系和其中的一些元类知识后,查看代码

serializer = TestSerializer(data=instance)

继续分析TestSerializer的初始化过程,

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) 												# 删除 many参数    super(BaseSerializer, self).__init__(**kwargs) 							# 调用Field的初始化方法Field的初始化方法def __init__(self, read_only=False, write_only=False,             required=None, default=empty, initial=empty, source=None,             label=None, help_text=None, style=None,             error_messages=None, validators=None, allow_null=False):    self._creation_counter = Field._creation_counter    Field._creation_counter += 1    # If `required` is unset, then use `True` unless a default is provided.    if required is None:        required = default is empty and not read_only    # Some combinations of keyword arguments do not make sense. 			# 进行相关逻辑的检查    assert not (read_only and write_only), NOT_READ_ONLY_WRITE_ONLY    assert not (read_only and required), NOT_READ_ONLY_REQUIRED    assert not (required and default is not empty), NOT_REQUIRED_DEFAULT    assert not (read_only and self.__class__ == Field), USE_READONLYFIELD    self.read_only = read_only    self.write_only = write_only    self.required = required    self.default = default    self.source = source    self.initial = self.initial if (initial is empty) else initial    self.label = label    self.help_text = help_text    self.style = {} if style is None else style    self.allow_null = allow_null    if self.default_empty_html is not empty:        if default is not empty:            self.default_empty_html = default    if validators is not None:        self.validators = validators[:]    # These are set up by `.bind()` when the field is added to a serializer.    self.field_name = None    self.parent = None    # Collect default error message from self and parent classes    messages = {}    for cls in reversed(self.__class__.__mro__):        messages.update(getattr(cls, 'default_error_messages', {}))    messages.update(error_messages or {})    self.error_messages = messages

当初始化完成后就执行了如下代码;

Response(serializer.data)

此时查看serializer.data的属性方法,由于ModelSerializer没有重写data属性所以就调用了Serializer的data属性;

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

由此本文的例子是传入的instance,在执行self.to_representation函数时,就传入了instance实例,

Serializer的to_representation方法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)       # 获取实例中对应的field字段        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)      # 否则调用field的to_representation来处理attribute    return ret      # 返回结果@cached_propertydef _readable_fields(self):    return [        field for field in self.fields.values()        if not field.write_only    ]                                                       # 在初始化的时候就获取只读的字段值    @propertydef 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.    if not hasattr(self, '_fields'):                        # 检查是否有_fields属性        self._fields = BindingDict(self)                                for key, value in self.get_fields().items():        # 调用get_fields获取字段属性值            self._fields[key] = value                       # 写入该值    return self._fields                                     # 返回该字段

由于由于此时是ModelSerializer此时调用了该类的get_fields方法;

def get_fields(self):    """    Return the dict of field names -> field instances that should be    used for `self.fields` when instantiating the serializer.    """    if self.url_field_name is None:                                     # 检查url_field_name        self.url_field_name = api_settings.URL_FIELD_NAME    assert hasattr(self, 'Meta'), (        'Class {serializer_class} missing "Meta" attribute'.format(            serializer_class=self.__class__.__name__        )    )                                                                   # 必须配置Meta属性    assert hasattr(self.Meta, 'model'), (        'Class {serializer_class} missing "Meta.model" attribute'.format(            serializer_class=self.__class__.__name__        )    )                                                                   # 必须在Meta中配置model属性    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 = getattr(self.Meta, 'model')                                 # 获取model    depth = getattr(self.Meta, 'depth', 0)                              # 获取深度信息    if depth is not None:                                               # 深度必须大于等于0小于等于10        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.    info = model_meta.get_field_info(model)                             # 获取model的信息    field_names = self.get_field_names(declared_fields, info)           # 获取filed字段名称    # 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        # Determine the serializer field class and keyword arguments.        field_class, field_kwargs = self.build_field(            field_name, info, model, depth        )                                                                       # Include any kwargs defined in `Meta.extra_kwargs`        extra_field_kwargs = extra_kwargs.get(field_name, {})        field_kwargs = self.include_extra_kwargs(            field_kwargs, extra_field_kwargs        )                                                               # 获取额外定义的字段        # Create the serializer field.        fields[field_name] = field_class(**field_kwargs)                # 创建额外字段的field实例    # 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:                                                              # 遍历属性列表        if instance is None:                                                        # 如果实例为空            # Break out early if we get `None` at any point in a nested lookup.            return None        try:            if isinstance(instance, collections.Mapping):                           # 检查是否为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 "{0}"; original exception was: {1}'.format(attr, exc))    return instance                                                                 # 返回

此时,在本例的序列化定义如下;

is_authorize = serializers.SerializerMethodField()    enterprise_name = serializers.SerializerMethodField()    enterprise_address = serializers.SerializerMethodField()    enterprise_name = serializers.CharField(        source='name')

此时需要渲染的字段有(“uuid”, “is_authorize”, “enterprise_name”, “enterprise_address”, “name”),

此时uuid和name两个字段值由于没有显示定义,则通过生成一个对应属性的filed实例来处理,此时就调用了filed的to_representation方法,其中serializers.SerializerMethodField定义如下;

class SerializerMethodField(Field):    """    A read-only field that get its representation from calling a method on the    parent serializer class. The method called will be of the form    "get_{field_name}", and should take a single argument, which is the    object being serialized.    For example:    class ExampleSerializer(self):        extra_info = SerializerMethodField()        def get_extra_info(self, obj):            return ...  # Calculate some data to return.    """    def __init__(self, method_name=None, **kwargs):        self.method_name = method_name                                      # 初始化 method_name默认为空        kwargs['source'] = '*'                                                  kwargs['read_only'] = True                                          # 设置read_only为True        super(SerializerMethodField, self).__init__(**kwargs)               # 调用父类的初始化方法    def bind(self, field_name, parent):        # In order to enforce a consistent style, we error if a redundant        # 'method_name' argument has been used. For example:        # my_field = serializer.SerializerMethodField(method_name='get_my_field')        default_method_name = 'get_{field_name}'.format(field_name=field_name)      # 获取默认的方法名称        assert self.method_name != default_method_name, (            "It is redundant to specify `%s` on SerializerMethodField '%s' in "            "serializer '%s', because it is the same as the default method name. "            "Remove the `method_name` argument." %            (self.method_name, field_name, parent.__class__.__name__)        )                                                                           # 如果定义的名称和名称相符则报错        # The method name should default to `get_{field_name}`.        if self.method_name is None:            self.method_name = default_method_name                                  # 判断是否使用默认的方法名称        super(SerializerMethodField, self).bind(field_name, parent)                 # 调用父类的bind方法    def to_representation(self, value):        method = getattr(self.parent, self.method_name)                     #  获取该方法        return method(value)                                                # 并将该值传入并执行

此时就调用了定义的方法;

def get_enterprise_name(self, obj):        enterprise_name = obj.name        return enterprise_name

等自定义的方法,此时就获取了所有的序列化数据,至此一个简单的Serializer的过程就基本执行完成。

总结

本文只是简单的分了一下ModelSerializer的序列化过程,Serializer的序列化还包括了数据的创建更新等更丰富的操作,再次就没有一一列举,大家有兴趣课自行分析,由于水平有限,如有疏漏请批评指正。

转载地址:https://blog.csdn.net/qq_33339479/article/details/83035206 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Django项目test中的mock概述
下一篇:djangorestframework源码分析1:generics中的view执行流程

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年03月26日 02时59分07秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章