drf之序列化source的使用、定制字段的两种方、多表关联反序列化保存、ModelSerializer使用

一、on_delete属性的补充

CASCADE:
级联删除,只要删除publish,跟publish关联的book,全都被删除
SET_DEFAULT:
只要删除publish,跟publish关联的book,的publish字段会变成默认值,一定要配合default使用
SET_NULL:
只要删除publish,跟publish关联的book,的publish字段会变成空,一定要配合null=True使用
models.SET(add):
括号中可以放个值,也可以放个函数内存地址,只要删除publish,跟publish关联的book,的publish字段会变成set设的值或执行函数
models.DO_NOTHING:
什么都不做,但它需要跟db_constraint=False配合,表示不建立外键约束,创建逻辑外键,不是物理外键

  • 不建立物理外键的好处?增删查改数据快
  • 缺点:容易出现脏数据
  • 实际工作中,都不建立物理外键,都是建立逻辑外键

二、序列化高级用法之source(了解)

1 创建了5个表(图书管理的5个)
2 对booke进行序列化

总结:source的用法

-1 修改前端看到的字段key值---》source指定的必须是对象的属性
	book_name = serializers.CharField(source='name')
-2 修改前端看到的value值,---》source指定的必须是对象的方法
	表模型中写方法
      def sb_name(self):
    	return self.name + '_sb'
    序列化类中
    	book_name = serializers.CharField(source='sb_name')
        
 -3 可以关联查询(得有关联关系)
	publish_name = serializers.CharField(source='publish.name')

source的用法

class BookSerialzier(serializers.Serializer):
    # 写的这些字段类的名字,必须是book对象中的属性,所以book_name会报错
    # 如果不想报错,使用source指定book对象中的属性
    # 第一种用法:放一个对象的属性
    book_name = serializers.CharField(source='name')  # 给前端看到的是 book_name
    name = serializers.CharField(source='name')  # 坑,会报错
    name = serializers.CharField()  # 同一个字段,可以序列化多次,但一般不会写

    # 第二种用法:放一个对象的方法  book.sb_name()--->真正的书名_sb
    # 方法写在models.py  Book里面
    book_name = serializers.CharField(source='sb_name')

    # 第三种:关联查询,拿出出版社的名字
    xx = serializers.CharField(source='publish.name')

    name = serializers.CharField()
    price = serializers.CharField()

三、序列化高级用法之定制字段的两种方式(非常重要)

方法总结

方式一:在序列化类中写

1 写一个字段,对应的字段类是:SerializerMethodField
2 必须对应一个 get_字段名的方法,方法必须接受一个obj,返回什么,这个字段对应的value就是什么

2、1 定制字段方式1

class BookSerialzier(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    # 拿出出版社的id和名字和addr,放到一个字典中
    # 方式一:SerializerMethodField来定制,如果写了这个,必须配合一个方法get_字段名,这个方法返回什么,这个字段的值就是什么
    publish_detail = serializers.SerializerMethodField()

    def get_publish_detail(self, book):
        # print(obj) # 要序列化的book对象
        return {'id': book.publish.pk, 'name': book.publish.name, 'addr': book.publish.addr}

    # 练习:拿出所有作者的信息--》多条 [{name:,phone:},{}]
    author_list = serializers.SerializerMethodField()

    def get_author_list(self, book):
        l = []
        for author in book.authors.all():
            l.append({'id': author.pk, 'name': author.name, 'phone': author.phone, 'age': author.author_detail.age})
        return l

方式二:在表模型中写

1 在表模型中写一个方法(可以使用:property),方法有返回值(字典,字符串,列表)
    @property
    def publish_detail(self):
        return {'id': self.publish.pk, 'name': self.publish.name, 'addr': self.publish.addr}

    def author_list(self):
        l = []
        for author in self.authors.all():
            l.append({'id': author.pk, 'name': author.name, 'phone': author.phone, 'age': author.author_detail.age})
        return l
2 在序列化类中,使用DictField,CharField,ListField
### 2.2 定制字段方式2
class BookSerialzier(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    # 1 序列化类中这样写
    # 2 到表模型中写一个方法,方法名必须叫 publish_detail,这个方法返回什么,这个字段的value就是什么
    publish_detail = serializers.DictField()

    author_list = serializers.ListField()

四、多表关联反序列化保存

序列化和反序列化,用的同一个序列化类
-序列化的字段有:name,price , publish_detail,author_list
-反序列化字段:name,price ,publish,author

4.1 反序列化之保存

视图类

class BookView(APIView):
    def post(self, request):
        ser = BookSerialzier(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})

序列化类

class BookSerialzier(serializers.Serializer):
    # 即用来做序列化,又用来做反序列化
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()

    # 这俩,只用来做序列化
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    # 这俩,只用来做反序列化
    publish_id = serializers.IntegerField(write_only=True)
    authors = serializers.ListField(write_only=True)

    def create(self, validated_data):  # {name:西游记,price:88,publish:1,authors:[1,2]
        authors = validated_data.pop('authors')
        book = Book.objects.create(**validated_data)
        book.authors.add(*authors)
        book.save()
        return book

4.2 反序列化之修改

视图类

class BookDetailView(APIView):
    def get(self, request ,pk):
        book = Book.objects.all().get(pk=pk)
        ser = BookSerializer(book)
        return Response({'code': 100, 'msg': '成功',
                         'data': ser.data})

    def put(self, request, pk):
        book = Book.objects.get(pk=pk)
        ser = BookSerializer(data=request.data,instance=book)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '更新成功'})
        else:
            return Response({'code': 100, 'msg': ser.errors})


    def delete(self,request,pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})

序列化类

class BookSerialzier(serializers.Serializer):
    # 即用来做序列化,又用来做反序列化
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()

    # 这俩,只用来做序列化
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    # 这俩,只用来做反序列化
    publish_id = serializers.IntegerField(write_only=True)
    authors = serializers.ListField(write_only=True)


    def update(self, instance, validated_data):
        authors = validated_data.pop('authors')
        for item in validated_data:
            setattr(instance, item, validated_data[item])
        instance.authors.set(authors)
        instance.save()
        return instance

五、反序列化字段校验其他

视图类中调用:ser.is_valid()---》触发数据的校验
-4层
-字段自己的:max_length,required。。。
-字段自己的:配合一个函数name = serializers.CharField(max_length=8,validators=[xxx])
-局部钩子
-全局钩子

六、ModelSerializer使用

之前写的序列化类,继承了Serializer,写字段,跟表模型没有必然联系

class XXSerialzier(Serializer)
id=serializer.CharField()
name=serializer.CharField()

XXSerialzier既能序列化Book,又能序列化Publish

现在学的ModelSerializer,表示跟表模型一一对应,用法跟之前基本类似

1 写序列化类,继承ModelSerializer
2 在序列化类中,再写一个类,必须叫
	class Meta:
		model=表模型
         fields=[] # 要序列化的字段
3 可以重写字段,一定不要放在class Meta
	-定制字段,跟之前讲的一样
4 自定制的字段,一定要在fields中注册一下
5 class Meta: 有个extra_kwargs,为某个字段定制字段参数
6 局部钩子,全局钩子,完全一致
7 大部分请情况下,不需要重写 create和update了
# 5 ModelSerialzier的使用

class BookSerialzier(serializers.ModelSerializer):
    # 第一个好处,不用一个个写字段了,把表模型中得字段映射过来
    class Meta:
        model = Book  # 指定表模型
        # fields='__all__'  # 把表模型中所有字段都映射过来
        fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']  # 自定制的字段,一定要在这里注册一下
        extra_kwargs = {
            'name': {'max_length': 10, 'required': True},
            'publish': {'write_only': True},
            'authors': {'write_only': True}
        }

    # 自定制字段:publish_detail  author_list 写法有两种,跟之前一模一样
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

    # 反序列化新增

    # 全局钩子和局部钩子,跟之前完全一样
posted @ 2023-05-18 19:46  岳宗柯  阅读(139)  评论(0编辑  收藏  举报