10 DRF-序列化

1 序列化数据

1-1 serializer

from django.db import models


class Depart(models.Model):
    title = models.CharField(verbose_name='部门', max_length=32)
    order = models.IntegerField(verbose_name='顺序')
    count = models.IntegerField(verbose_name='人数')
from rest_framework import serializers
from api import models


class DepartSerializer(serializers.Serializer):
    title = serializers.CharField()
    count = serializers.IntegerField()

class DepartView(APIView):
    def get(self, request, *args, **kwargs):
        # 1.数据库获取单条数据
        # depart_obj = models.Depart.objects.all().first()
        # ser = DepartSerializer(instance=depart_obj)  # 默认many=False
        # print(ser.data)  # {'title': '技术部', 'count': 10}

        # 2.数据库获取多条数据
        query_set = models.Depart.objects.all()
        ser = DepartSerializer(instance=query_set, many=True)
        print(ser.data)
        # [OrderedDict([('title', '技术部'), ('count', 10)]), OrderedDict([('title', '运营部'), ('count', 11)])]

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

1-2 ModelSerializer

from django.db import models


class Depart(models.Model):
    title = models.CharField(verbose_name='部门', max_length=32)
    order = models.IntegerField(verbose_name='顺序')
    count = models.IntegerField(verbose_name='人数')
from rest_framework import serializers
from api import models


class DepartSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Depart
        fields = '__all__'


class DepartView(APIView):
    def get(self, request, *args, **kwargs):
        # 1.数据库获取单条数据
        # depart_obj = models.Depart.objects.all().first()
        # ser = DepartSerializer(instance=depart_obj)  # 默认many=False
        # print(ser.data)  # {'title': '技术部', 'count': 10}

        # 2.数据库获取多条数据
        query_set = models.Depart.objects.all()
        ser = DepartSerializer(instance=query_set, many=True)
        print(ser.data)
        # [OrderedDict([('title', '技术部'), ('count', 10)]), OrderedDict([('title', '运营部'), ('count', 11)])]


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

1-3 字段和参数

from django.db import models

class Depart(models.Model):
    title = models.CharField(verbose_name='部门', max_length=32)
    order = models.IntegerField(verbose_name='顺序')
    count = models.IntegerField(verbose_name='人数')

class UserInfo(models.Model):
    name = models.CharField(verbose_name='姓名', max_length=32)
    age = models.IntegerField(verbose_name='年龄')

    gender = models.SmallIntegerField(verbose_name='性别', choices=((1, '男'), (2, '女')))
    depart = models.ForeignKey(verbose_name='部门', to='Depart', on_delete=models.CASCADE)
    ctime = models.DateTimeField(verbose_name='时间', auto_now_add=True)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models

class UserSerializer(serializers.ModelSerializer):
    gender_text = serializers.CharField(source='get_gender_display')  # choices
    depart = serializers.CharField(source='depart.title')  # FK
    ctime = serializers.DateTimeField(format="%Y-%m-%d")  # 时间格式化

    xxx = serializers.SerializerMethodField()  # 自定义显示数据

    class Meta:
        model = models.UserInfo
        fields = ['name', 'age', 'gender', 'gender_text', 'depart', 'ctime', 'xxx']

    def get_xxx(self, obj):
        # obj是每一行的数据,可以.出想要的字段
        # queryset = models.UserInfo.objects.all()
        return '{}-{}-{}'.format(obj.name, obj.age, obj.gender)


class UserView(APIView):
    def get(self, request, *args, **kwargs):
        queryset = models.UserInfo.objects.all()
        ser = UserSerializer(instance=queryset, many=True)

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

image


1-4 序列化类嵌套

主要是ORM类中对应ForeignKeyManyToManyField的字段进行序列化。

  • 基于SerializerMethodField自定义方法对关联表数据进行序列化
  • 基于嵌套的序列化类实现

image

image


1-5 序列化类继承

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models


class Base(serializers.Serializer):
    xx = serializers.CharField(source='name')


class UserSerializer(serializers.ModelSerializer, Base):
    class Meta:
        model = models.UserInfo
        fields = ['name', 'age', 'xx']


class UserView(APIView):
    def get(self, request, *args, **kwargs):
        queryset = models.UserInfo.objects.all()
        ser = UserSerializer(instance=queryset, many=True)

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

image


1-6 底层实现原理(扩展)

声明:掌握上述知识点,已经可以让你完成工作中常见的任务。接下来的知识点,只是作为扩展,可以略过。

1.元类

对象是通过类实例化出来的。

class Foo(object):
    pass

# 第1步:调用Foo的__new__方法创建空对象。
# 第2步:调用Foo的__init__方法对对象进行初始化。
obj = Foo()

类是谁创建的?是由type创建出来的(默认)。

class Foo(object):
    v1 = 123
    
    def func(self):
        return 666
Foo = type("Foo",(object,),{ "v1":123, "func":lambda self:666 })

定义类时加入metaclass指定当前类的创造者。

# 由type创建Foo类型
class Foo(object):
    pass
# 由`东西` 创建Foo类型
class Foo(object,metaclass=东西):
    pass

指定元类(metaclass) 来创建类。

class MyType(type):
    def __new__(cls, *args, **kwargs):
        new_cls = super().__new__(cls, *args, **kwargs)
        print("创建类:", new_cls)
        return new_cls

class Foo(metaclass=MyType):
    pass
class MyType(type):
    def __init__(self, *args, **kwargs):
        print("第2步:初始化类成员:", args, **kwargs)
        super().__init__(*args, **kwargs)

    def __new__(cls, *args, **kwargs):
        new_cls = super().__new__(cls, *args, **kwargs)
        print("第1步:创建类:", new_cls)
        return new_cls


class Foo(metaclass=MyType):
    v1 = 123

    def func(self):
        pass
class MyType(type):
    def __init__(cls, *args, **kwargs):
        print("第2步:初始化类成员:", args, **kwargs)
        super().__init__(*args, **kwargs)

    def __new__(cls, *args, **kwargs):
        new_cls = super().__new__(cls, *args, **kwargs)
        print("第1步:创建类:", new_cls)
        return new_cls

    def __call__(cls, *args, **kwargs):
        print("第3步:创建对象&初始化对象", cls)

        # 1.调用自己那个类的 __new__ 方法去创建对象
        new_object = cls.__new__(cls, *args, **kwargs)

        # 2.调用你自己那个类 __init__放发去初始化
        cls.__init__(new_object, *args, **kwargs)
        return new_object


class Foo(metaclass=MyType):
    v1 = 123

    def func(self):
        pass


obj = Foo()
2.实例化字段对象
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models


class InfoSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField()
    order = serializers.IntegerField

对于上述代码,在类InfoSerializer创建之前,其内部id、title、order字段会先进行实例化对象。

而这些IntegerFieldCharField等字段的继承关系如下:

class Field:
    _creation_counter = 0
    
class IntegerField(Field):
    pass

class CharField(Field):
    pass

class DateTimeField(Field):
    pass

IntegerFieldCharField等字段实例化时,内部会维护一个计数器,来表示实例化的先后顺序。

class Field:
    _creation_counter = 0
	def __init__(self, *, read_only=False...):
        self._creation_counter = Field._creation_counter
        Field._creation_counter += 1
        
class IntegerField(Field):
	def __init__(self, **kwargs):
        ...
        super().__init__(**kwargs)

class CharField(Field):
	def __init__(self, **kwargs):
        ...
        super().__init__(**kwargs)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from api import models


class InfoSerializer(serializers.Serializer):
    id = serializers.IntegerField()  # 对象,内部_creation_counter=0
    title = serializers.CharField()  # 对象,内部_creation_counter=1
    order = serializers.IntegerField # 对象,内部_creation_counter=2

注意:后续会通过这个计数器排序,以此来实现字段的先后执行。

3.序列化类的创建
class SerializerMetaclass(type):
	def __new__(cls, name, bases, attrs):
        attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)
        return super().__new__(cls, name, bases, attrs)
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
	...

class ModelSerializer(Serializer):
	...
    
class RoleSerializer(serializers.ModelSerializer):
    gender = serializers.CharField(source="get_gender_display")
    class Meta:
        model = models.Role
        fields = ["id", 'title',"gender"]

注意:父类中指定metaclass,子类也会由此metaclass来创建类。

4._declared_fields

在创建类之前,元类的__new__方法在类成员中添加了一个_declared_fields(类变量)。

class SerializerMetaclass(type):
    @classmethod
    def _get_declared_fields(cls, bases, attrs):
        # 1.循环获取类中定义所有的成员(类变量、方法),筛选出继承自Fields的类的字段对象。
        # 注意:同时会将字段在当前类成员中移除
        fields = [
            (field_name, attrs.pop(field_name)) 
            for field_name, obj in list(attrs.items())
            if isinstance(obj, Field)
        ]
        # 2.根据字段的_creation_counter排序
        fields.sort(key=lambda x: x[1]._creation_counter)

        # Ensures a base class field doesn't override cls attrs, and maintains
        # field precedence when inheriting multiple parents. e.g. if there is a
        # class C(A, B), and A and B both define 'field', use 'field' from A.
        known = set(attrs)

        def visit(name):
            known.add(name)
            return name
		
        # 3.读取父类中的_declared_fields字段(父类先于子类创建、序列化类支持继承)
        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
        ]
		
        # 4.将父类和子类中的字段打包返回,赋值给当前类的_declared_fields
        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)
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
	...

class ModelSerializer(Serializer):
	...
    
class RoleSerializer(serializers.ModelSerializer):
    gender = serializers.CharField(source="get_gender_display")
    class Meta:
        model = models.Role
        fields = ["id", 'title',"gender"]

所以,当类序列化类加载完毕后,类中成员:

  • 剔除,字段对象。

    RoleSerializer.gender   不存在
    
  • 新增,_declared_fields,是OrderedDict类型且内部包含所有字段。

    RoleSerializer._declared_fields = {
        "gender": CharField对象
    }
    
  • 其他,保留原样。

    RoleSerializer.Meta
    
5.创建序列化类对象

在视图的方法,使用序列化类对 orm 获取的QuerySet或对象进行序列化时,需要先进行初始化类的对象。

class SerializerMetaclass(type):
	def __new__(cls, name, bases, attrs):
        attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)
        return super().__new__(cls, name, bases, attrs)
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):
        if kwargs.pop('many', False):
            # 调用 many_init 方法获取其他对象,返回
            return cls.many_init(*args, **kwargs)

        # 创建当前类的空对象,返回
        return super().__new__(cls, *args, **kwargs)


    @classmethod
    def many_init(cls, *args, **kwargs):
		...
        child_serializer = cls(*args, **kwargs)
        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)
    
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
	...

class ModelSerializer(Serializer):
	...
    
class RoleSerializer(serializers.ModelSerializer):
    gender = serializers.CharField(source="get_gender_display")
    class Meta:
        model = models.Role
        fields = ["id", 'title',"gender"]
instance = models.UserInfo.objects.all().first()

# 实例化对象,内部会:先执行__new__、再执行__init__
# 第1步:__new__
# 	默认:many=True,返回ListSerializer对象; many=False,返回当前类InfoSerializer的对象。
# 第2步:__init__
#   此处就要根据__new__返回的不同对象,执行不同对象的__init__方法。
# =====> 思考题:你觉得他为什么要这么设计? <======
ser = InfoSerializer(instance=instance, many=False)

# 获取序列化后的值
ser.data
6.序列化-当前类
class Field:
    def get_attribute(self, instance):
        # source_attrs=[]  或 source_attrs=["xx","xx","xxx"]
		return get_attribute(instance, self.source_attrs)
    
class CharField(Field):
    def to_representation(self, value):
        return str(value)
class BaseSerializer(Field):
    @property
    def data(self):
        # 第2步
        if not hasattr(self, '_data'):
            if self.instance is not None and not getattr(self, '_errors', None):
                # 第3步:用于序列化给对象进行初始化用的。
                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:
                # 这个是用于给Serializer,不传对象而传入initial_data参数用的。
                self._data = self.get_initial()
        return self._data

class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
    @property
    def data(self):
        # 第1步
        ret = super().data
        return ReturnDict(ret, serializer=self)
	
    def to_representation(self, instance):
        # 第4步
        ret = OrderedDict()
        
        # 第5步:获取 _declared_fields 中所有非write_only字段,即:用于序列化的字段。
        #       如果是ModelSerializer,也会去寻找其Meta中定义的字段 + 字段的bind方法
        fields = self._readable_fields

        for field in fields:
            try:
                # 第5步:调用字段对象中的 get_attribute 方法
                attribute = field.get_attribute(instance)
            except SkipField:
                continue

            check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
            if check_for_none is None:
                ret[field.field_name] = None
            else:
                # 第6步:调用字段对象中的 to_representation 方法
                ret[field.field_name] = field.to_representation(attribute)

        return ret
    
class ModelSerializer(Serializer):
	...
    
class RoleSerializer(serializers.ModelSerializer):
    gender = serializers.CharField(source="get_gender_display")
    class Meta:
        model = models.Role
        fields = ["id", 'title',"gender"]
instance = models.UserInfo.objects.all().first()
ser = InfoSerializer(instance=instance, many=False)

# 创建InfoSerializer类的对象,获取序列化后的值
ser.data
7.序列化-ListSerializer
class BaseSerializer(Field):
    @property
    def data(self):
        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

class ListSerializer(BaseSerializer):
	@property
    def data(self):
        ret = super().data
        return ReturnList(ret, serializer=self)
    
    def to_representation(self, data):
        iterable = data.all() if isinstance(data, models.Manager) else data
        
        return [
            # 循环,利用序列化类去处理每个对象
            self.child.to_representation(item) for item in iterable
        ]

posted @ 2022-10-20 10:52  角角边  Views(42)  Comments(0)    收藏  举报