郑统京 发表于 2022-12-16 01:07:30

初始Django序列化组件Serializer

# Serializer类,如何序列化
1、需要序列化什么,必须写一个类继承serializer.Serializer
2、像序列化什么字段,就在类里面写什么字段,一般情况下序列化的字段和models都是一样的,但是想写不一样的就可以通过source='字段名'来控制
的3个作用(很多字段类)]
    修改字段名
    隐藏的book.方法,eg:source="publish.email" ==> book.publish.email
    执行类的方法 类的绑定方法
3、序列化queryset(列表也可以,因为queryset继承了列表)和真正的对象
    1、序列化得到一个字段,序列化对象.data
      book_ser=BookSerializer(对象)
      Response(book_ser.data)
    2、自己封装Response方法
      class MyResponse():
            def __init__(self):
                self.status=100
                self.msg='成功'
            @property
            def get_dict(self):
                return self.__dict__
      if __name__ == "__main__"
            res=MyResponse()
            res.data={'name':'lqz'} #对象给他的data属性加值,会自动保存到__init__里面去,在后面导入这个模块就可以了,然后需要该值就生成对象,res=MyResponse(),res.status=102就可以了
            res.get_dict
            print()
4、反序列化 view中的put方法 book_ser=BookSerializer(instance=要序列化的对象,data= request.data)
、字段验证顺序:]
    1、序列化类中,给字段加属性,
    2、局部和全局钩子函数,
    3、写一个函数,在Serializer字段中加入validators=[函数地址]
    4、调用is_valid()就会走验证,先走字段验证完,在走局部钩子,循环结束完,最后再走全局钩子,所以可以总结出来,在全局的Validate数据是符合上面的规则的数据
    5、*了解*:is_valid(),里面加入raise_exception=True只要验证不通过就直接抛异常,不会去捕获了
6、修改保存---》调用序列化对象.save(),但是要重写Serializer类的update方法,有一个一个字段去核对
    def update(self, instance, validated_data):
      # instance是book的这个对象
      # validated_data是校验后的数据
      instance.name=validated_data.get('name')
      instance.price=validated_data.get('price')
      instance.author=validated_data.get('author')
      instance.publish=validated_data.get('publish')
      instance.save() # instance这个是book对象=orm提供的save()
      return instance # 后续可能需要用到所以返回回去
    [*补充说明*]
      如果前端传过来的数据的字段不是在同一张表,那么我们需要通过instance.字段把对象取出来,然后进行orm的保存操作create

7、反序列化的新增
    1、和反序列化新增的差别就在与没有instance这个修改对象
    2、book_ser=BookSerializer(data= request.data),通过源码可以看到一定要写data=request.data要不然会把这个传给了instance了
    、源码可知,当序列化对象(book_ser).save()时候:
      、当同时在字段中有instance和data的时候会自动调用update方法,-
      、只有data的时候会调用create方法]
            重写create可以很复杂
            # ser.py 序列化类重写create方法
            def create(self, validated_data):# 传统意义需要一个一个关键字传入,但是现在**打散会更加合适
                instance = Book.objects.create(**validated_data)
                return instance
            *补充*
                中如如果有一些数据是不必要的,可以通过.pop('key')删除]

8、ModelSerializer 跟模型做对应
      1、基本用法
            class BookModelSerializer(serializers.ModelSerializer):
                def validate_price(self, data):
                  pass
                publish=serializers.CharField(source='publish.name')
                [class Meta:
                  model=Book# 对应上models.py中的模型]
                  fields='__all__' [序列化全部字段]
                  # fields=('name','price','id','author','publish') # 只序列化指定的字段
                  # exclude=('name',) #跟fields不能都写,写谁,就表示排除谁
                  # read_only_fields=('price',)
                  # write_only_fields=('id',) #弃用了,使用extra_kwargs
                  extra_kwargs = {# 类似于这种形式name=serializers.CharField(max_length=16,min_length=4)
                        'price': {'write_only': True,max_length:16,min_length:4},
                  }
                、字段自己的校验]
                直接通过extra_kwargs传过去 :
                [类似于这种形式name=serializers.CharField(max_length=16,min_length=4)==>'price': {'write_only': True,max_length:16,min_length:4}]
                ,相当于在之前Serializer中字段里面写了各种条件   
                、在类中写钩子函数]
                  跟之前一模一样,在class这个类下面写局部钩子
                  def validate_price(self, data):# validate_字段名接收一个参数
                        # 如果价格小于10,就校验不通过
                        # print(type(data))
                        # print(data)
                        if float(data) > 10:
                            return data
                        else:
                            # 校验失败,抛异常
                            raise ValidationError('价格太低')
                        # 全局钩子
                  def validate(self, validate_data):# 全局钩子
                        print(validate_data)
                        author = validate_data.get('author')
                        publish = validate_data.get('publish')
                        if author == publish:
                            raise ValidationError('作者名字跟出版社一样')
                        else:
                            return validate_data
                、如何通过对对象拿到对象的属性]
                fields=('name','price','id','author','publish')
                publish = serializer.Serializer(source="publish.name") 在ModelSerializer中自动会有class Meta:model=Book中的book对象,只是隐藏了
                这样就可以把publish覆盖了
                、自定义create和update方法]
                def create():
                  pass
                def update():
                  pass
                自己写完会优先用自己的方法
13、many源码,many=True能够序列化多条数据的原因
[序列化多条,需要传many=True]
book_ser=BookModelSerializer(books,many=True)
book_one_ser=BookModelSerializer(book)
print(type(book_ser))
#<class 'rest_framework.serializers.ListSerializer'> 这里面列表中对应的都是modelSerializer的对象
print(type(book_one_ser))
#<class 'app01.ser.BookModelSerializer'>
[核心思想]
# 对象的生成--》先调用类的__new__方法,生成空对象
# 对象=类名(name=lqz),触发类的__init__()
def __new__(cls, *args, **kwargs):
    if kwargs.pop('many', False):
      return cls.many_init(*args, **kwargs)
    # 没有传many=True,走下面,正常的对象实例化
    return super().__new__(cls, *args, **kwargs)
[补充魔法方法]
# 类的__new__方法控制对象的生成
# __str__ 当对象被打印的时候触发这个方法、
# __dict__ 类来调用会把类的属性组合成字典,对象.__dict__会把对象的属性组成字典
# __call__ 对象被调用会触发
# __getattr__ 独享点属性时候会被触发这个方法

14、接口:统一子类的行为(其他语言)
      python中推崇鸭子类型,子类写了该方法,就不用父类的了,但是接口的概念也是很有必要的统一规范如何实现:
            1、abc模块控制
            2、raise抛异常控制
页: [1]
查看完整版本: 初始Django序列化组件Serializer