DRF-django_rest_framework序列化器源码剖析

94 阅读7分钟

序列化源码流程

在创建类的时候,是先将成员变量和方法创建,将成员变量和方法作为参数传递给基类type()

class base(serializers.Serializer):
    id = serializers.IntegerField(source='id')
    name = serializers.CharField(source='name')

字段xx是先于base类创建的

1、创建成员变量

#第4部分会用到
def get_attribute(instance, attrs):
    #atrrs是source按.分个开的列表
    #depart = serializers.CharField(source='depart.title')
    #attrs=['depart','title']
    for attr in attrs:
        try:
            if isinstance(instance, Mapping):
                instance = instance[attr]
            else:
                #先获取depart对象赋值给instance,循环到第二次的时候从depart获取title
                instance = getattr(instance, attr)
        except ObjectDoesNotExist:
            return None
        if is_simple_callable(instance):	#是否可执行
            try:
                #gender_text = serializers.CharField(source='get_gender_display')
                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
class Field:
    _creation_counter = 0	#类变量
    def __init__(self, *,...):
        self._creation_counter = Field._creation_counter
        Field._creation_counter += 1
        
class IntegerField(Field):
    def __init__(self, **kwargs):
        self.max_value = kwargs.pop('max_value', None)
        self.min_value = kwargs.pop('min_value', None)
        #调用父类的__init__
        super().__init__(**kwargs)
        if self.max_value is not None:
            message = lazy_format(self.error_messages['max_value'], max_value=self.max_value)
            self.validators.append(
                MaxValueValidator(self.max_value, message=message))
        if self.min_value is not None:
            message = lazy_format(self.error_messages['min_value'], min_value=self.min_value)
            self.validators.append(
                MinValueValidator(self.min_value, message=message))
    def to_representation(self, value):
        return int(value)
    
    def bind(self, field_name, parent):
        #读取字段的source
        #name = serializers.CharField(source='name')
        #depart = serializers.CharField(source='depart.title') -->source_attrs=['depart','title']
        if self.source == '*':
            self.source_attrs = []
        else:
            self.source_attrs = self.source.split('.')
    # 4 部分会用到
    def get_attribute(self, instance):
        #source_attrs就是source的值,4部分的get_attritube就会获取instance.name等等
        #return 的get_attribute不是Field的方法
        return get_attribute(instance, self.source_attrs)

class CharField(Field):
    def __init__(self, **kwargs):
        self.allow_blank = kwargs.pop('allow_blank', False)
        self.trim_whitespace = kwargs.pop('trim_whitespace', True)
        self.max_length = kwargs.pop('max_length', None)
        self.min_length = kwargs.pop('min_length', None)
        #也调用父类的__init__
        super().__init__(**kwargs)
        ...
    def to_representation(self, value):
        return str(value)

        
id = serializers.IntegerField(source='id')	#{'max_value':xxx, '_creation_counter':0}

#等到name字段创建时,Field的_creation_counter+=1
name = serializers.CharField(source='name')  #{'allow_blank':xxx, '_creation_counter':1}

Field维护一个_creation_counter变量的意义是什么?

是根据编写的顺序来定义后续源码中各个字段的处理顺序。因为字典是无序的,当有校验的需求时应该要有固定的字段执行顺序

2、创建类


class base(serializers.Serializer):				#继承Serializer
    xx = serializers.IntegerField(source='count')
    name = serializers.CharField(source='name')
    
class D1(serializers.ModelSerializer):
    class Meta:
        model = models.Depart
        fields = ['id','title']    
        
#也是继承Serializer
class ModelSerializer(Serializer):
    ...
    
#由SerializerMetaclass创建
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
	...

class SerializerMetaclass(type):
    @classmethod
    def _get_declared_fields(cls, bases, attrs):
        #循环类的所有成员,isinstance(obj, Field)可以获取所有继承Field类的对象
        #isinstance(name,Field)			True
        #isinstance(name,CharField)		True
        
        #列表推导式获取Field对象之后pop将对象取出到元组里(field_name,Field对象)
        #fields = [('id',IntegerField对象),('xx',CharField对象)]
        fields = [(field_name, attrs.pop(field_name))
                  for field_name, obj in list(attrs.items())
                  if isinstance(obj, Field)]
        #根据对象的_creation_counter排序,这里的fields是自己的字段
        fields.sort(key=lambda x: x[1]._creation_counter)
		
        #元组去重
        known = set(attrs)

        def visit(name):
            known.add(name)
            return name
		
        #bases:父类,寻找父类的_declared_fields(在__new__时创建的),并转换成列表套元组
        base_fields = [
            (visit(name), f)
            for base in bases if hasattr(base, '_declared_fields')
            for name, f in base._declared_fields.items() if name not in known
        ]
		
        #返回自己的字段 + 父类的字段	的有序字典
        return OrderedDict(base_fields + fields)
    

        
    def __new__(cls, name, bases, attrs):
        #添加成员,内容是{自己的字段对象 + 父类的字段对象}
        attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)
        return super().__new__(cls, name, bases, attrs)

    

3、收到请求,查询数据库 + 序列化器

class UserView(APIView):
    def get(self,request,*args,**kwargs):
		#查询数据库获取并序列化
        queryset = models.UserInfo.objects.all()
		
        #many的值不同创建的类也是不同的
        ser = UserSerializer(instance=queryset,many=True)	#最终会使用BaseSerializer来创建类
        #ser = UserSerializer(instance=queryset,many=False)
        
class UserSerializer(serializers.ModelSerializer,base):
	...
class ModelSerializer(Serializer):
    ...
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
    ...
class BaseSerializer(Field):
    def __new__(cls, *args, **kwargs):
    #pop参数里的many,如果没有many择返回默认值False
    if kwargs.pop('many', False):
        return cls.many_init(*args, **kwargs)	#many=True,使用many_init,返回ListSerializer对象
    return super().__new__(cls, *args, **kwargs)#mant=False,返回当前对象UserSerializer
    def __init__(self, instance=None, data=empty, **kwargs):
        self.instance = instance
        
    @classmethod
    def many_init(cls, *args, **kwargs):
        allow_empty = kwargs.pop('allow_empty', None)
        max_length = kwargs.pop('max_length', None)
        min_length = kwargs.pop('min_length', None)
        #实例化当前类:UserSerializer()
        child_serializer = cls(*args, **kwargs)
        list_kwargs = {
            'child': child_serializer,
        }
        if allow_empty is not None:
            list_kwargs['allow_empty'] = allow_empty
        if max_length is not None:
            list_kwargs['max_length'] = max_length
        if min_length is not None:
            list_kwargs['min_length'] = min_length
        list_kwargs.update({
            key: value for key, value in kwargs.items()
            if key in LIST_SERIALIZER_KWARGS
        })
        #读取Meta成员
        meta = getattr(cls, 'Meta', None)
        #读取Meta里的list_serializer_class
        list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
        #返回一个实例化对象list_serializer_class(),将实例化的当前对象child_serializer()当做参数传递	
        return list_serializer_class(*args, **list_kwargs)

4、触发序列化ser.data(many=False的情况)

class UserView(APIView):
    def get(self,request,*args,**kwargs):

        queryset = models.UserInfo.objects.all()

        ser = UserSerializer(instance=queryset,many=False)
        
class UserSerializer(serializers.ModelSerializer,base):
	...
class ModelSerializer(Serializer):
    def get_fields(self):
		...
		#深拷贝_declared_fields
        declared_fields = copy.deepcopy(self._declared_fields)
        #寻找model字段,model = models.UserInfo
        model = getattr(self.Meta, 'model')
        depth = getattr(self.Meta, 'depth', 0)
		...
        #将数据库的字段都获取
        info = model_meta.get_field_info(model)
        field_names = self.get_field_names(declared_fields, info)#读取fields,获取数据库对应的字段

        # 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:		#如果字段在models的类名里,直接添加到fields
            # 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

            #如果字段名不在数据库,则根据对应关系创建,build_field会调用build_standard_field,里面会根据serializer_field_mapping的对应关系创建
            #models.CharField对应Serializer的CharField
            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.
            fields[field_name] = field_class(**field_kwargs)

        # Add in any hidden fields.
        fields.update(hidden_fields)
		#返回创建的字段对应的对象
        return fields
    
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):

    @cached_property
    def fields(self):
        fields = BindingDict(self)
        #循环self.get_fields,会先在子类ModelSerializer找,get_fields返回的包括自己定义的字段和Meta的Fields的字段
        for key, value in self.get_fields().items():
            fields[key] = value
        return fields
    @property
    def _readable_fields(self):
        #循环self.fields,并返回
        for field in self.fields.values():
            if not field.write_only:
                yield field
                
	#序列化功能,由data触发
    def to_representation(self, instance):
        ret = OrderedDict()		#有序字典
        fields = self._readable_fields	#获取所有的字段,在第2部分的UserSerializer._get_declared_fields + 读取Meta里的fields字段并创建对象
		
        #循环所有的对象
        for field in fields:
            ...
            #执行每个字段的get_attribute--(IntegerField.get_attribute)->在第一部分
			#获取数据库对应的字段
            attribute = field.get_attribute(instance)
            #调用每个field的to_representation,整形转换成整形,char->str...
            '''
            class IntegerField(Field):
                def to_representation(self, value):
        		return int(value)
            '''
            ret[field.field_name] = field.to_representation(attribute)

        return ret
    
    @property
    def data(self):
        ret = super().data	#调用父类的data
        return ReturnDict(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.'
            )
            raise AssertionError(msg)
        if not hasattr(self, '_data'):
            #instance在调用序列化器时就已经传递
            if self.instance is not None and not getattr(self, '_errors', None):
                #序列化的功能to_representation,在子类Serializer
                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

流程:

实例化UserSerializer类,UserSerializer的data由@property装饰,调用父类的data。在BaseSerializer类才有data方法,执行data时会用到子类Serializer的to_representation,这个方法会调用_readable_fields通过get_fields获取declared_fields的字段和Meta的字段并实例化成对象,返回给to_representation,to_representation根据字段名(通过get_attritube获取到数据库对应的值)获取值,再返回给有序字典data。

5、触发序列化ser.data(many=True的情况)

class UserView(APIView):
    def get(self,request,*args,**kwargs):

        queryset = models.UserInfo.objects.all()

        ser = UserSerializer(instance=queryset,many=True)

        context = {'status': 200, 'data': ser.data}
        return Response(context)

class BaseSerializer(Field):
    def __new__(cls, *args, **kwargs):
        if kwargs.pop('many', False):
            return cls.many_init(*args, **kwargs)	#many = True,->many_init()
        return super().__new__(cls, *args, **kwargs)
    
    
    @classmethod
    def many_init(cls, *args, **kwargs):
        child_serializer = cls(*args, **kwargs)
        list_kwargs = {
            'child': child_serializer,}			#将当前类UserSerializer当做参数传递给list_serializer_class->list_kwargs:{'child': child_serializer}
        
        meta = getattr(cls, 'Meta', None)
        list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
        return list_serializer_class(*args, **list_kwargs)
    
   
	@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):
                #执行到这也会调用to_representation,会找到子类ListSerializer的此方法
                self._data = self.to_representation(self.validated_data)
            else:
                self._data = self.get_initial()
        return self._data
    
    
    
#many=True的情况调用ser.data    
class ListSerializer(BaseSerializer):

    ...
    child = None
    many = True
    @property
    def __init__(self, *args, **kwargs):
        self.child = kwargs.pop('child', copy.deepcopy(self.child))
    def data(self):
        ret = super().data				#调用父类的data
        return ReturnList(ret, serializer=self)
    
    def to_representation(self, data):
        iterable = data.all() if isinstance(data, models.Manager) else data
		#列表生成式,循环调用当前类的to_representation
        return [
            self.child.to_representation(item) for item in iterable
        ]

        

many=True的情况就是第4部分加上一个循环。

屏幕截图 2024-02-06 140855.png 图片来源:武佩齐老师