• django——Serializer的反序列化、字段与参数、局部与全局钩子、ModelSerializer使用


    系列文章目录

    drf
    第一章 django web开发模式、api接口、api接口测试工具、restful规范、序列化反序列化、drf安装使用

    第二章 drf的使用、APIView源码分析、Request源码分析、Serializer的序列化

    第三章 Serializer的反序列化、字段与参数、局部与全局钩子、ModelSerializer使用



    一、Serializer的反序列化

    使用serializer序列化器时,反序列化一般针对update和create,所以如果有对应表主键时最好为其设置read_only为True

    表中无外间关系时可以使用serializer或者ModelSerializer
    此处展示Serializer使用方式
    表关系:

    	
    	class Book(models.Model):
        bname = models.CharField(max_length=20, verbose_name='书籍名称')
        price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name='书籍单价')
    
        def __str__(self):
            return self.bname
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    对应的Serializer序列化器
    针对于Serializer创建与更新方法需要重写,删除、查询、查询单个需要在视图类中完成

    	
    	class BookSerializer(serializers.Serializer):
        bname = serializers.CharField(max_length=20)
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
    	
        def update(self, instance, validated_data):
            instance.bname = validated_data.get('bname')
            instance.price = validated_data.get('price')
            instance.save()
            return instance
    
        def create(self, validated_data):
            book_obj = Book.objects.create(**validated_data)
            return book_obj
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    对应视图类

    	class BookApiView(views.APIView):
    
        def get(self,request):
            dict = {{'code':200, 'msg':'查询成功成功'}}
            if not request.query_params:
                books = Book.objects.all()
                dict['msg'] = '查询全部书籍成功'
            else :
                books = Book.objects.filter(pk=request.query_params.get('id'))
                dict['msg'] = '查询一本书籍成功'
            bookSerializer = BookSerializer(instance=books, many=True)
            dict['data'] = bookSerializer.data
            return Response(dict)
    
        def delete(self,request):
            dict = {'code':200}
            pk = request.data.get('id')
            if pk:
                book_obj = Book.objects.filter(pk=pk)
                if book_obj:
                    book_obj.delete()
                    dict['msg'] = '删除成功'
                    dict['data'] = ''
                else :
                    dict['code'] = 10003
                    dict['msg'] = '该书不存在,无法删除'
            else:
                dict['code'] = 10004
                dict['msg'] = '请指定书籍id'
            return Response(dict)
    
        def put(self,request):
            dict = {'code': 200}
            book_obj = Book.objects.filter(pk=request.data.get('id')).first()
            if book_obj:
                bookSerializer = BookSerializer(instance=book_obj, data=request.data)
                if bookSerializer.is_valid():
                    bookSerializer.save()
                    dict['msg'] = '修改成功'
                    dict['data'] = bookSerializer.data
                else:
                    dict['code'] = 10001
                    dict['msg'] = '修改失败,数据未通过验证'
                    dict['errors'] = bookSerializer.errors
            else:
                dict['code'] = 10002
                dict['msg'] = '不存在该书籍'
                dict['errors'] = '找不到对应的书籍id'
            return Response(dict)
    
        def post(self,request):
            print(request.FILES)
            dict = {'code': 200}
            bookSerializer = BookSerializer(data=request.data)
            if bookSerializer.is_valid():
                bookSerializer.save()
                dict['msg'] = '创建成功'
                dict['data'] = bookSerializer.data
            else:
                dict['code'] = 10005
                dict['msg'] = '数据验证未通过'
                dict['errors'] = bookSerializer.errors
            return Response(dict)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    二、Serializer字段与参数

    常见字段与models基本一致
    常用参数:
    read_only:True 不设置时默认为False 作用是只在序列化时产生该字段数据
    write_only:True 不设置时默认为False 作用是只在反序列化时需要该字段数据
    error_messages 设置该字段检验不通过的错误信息
    depth 连表查询深度


    三、Serializer局部和全局钩子

    局部钩子是重写validate_字段名 函数
    需要抛出错误时使用ValidationError
    通过验证时返回对应的字段

    
        def validate_pname(self, pname):
            if re.findall('京东', pname):
                raise ValidationError('出版社名字不能包含京东')
            else:
                return pname
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    全局钩子是重写validate函数 在全局钩子中attrs是对应序列化器中的所有字段
    需要抛出错误时使用ValidationError
    通过验证时返回对应的attrs

    
        def validate(self, attrs):
            if re.findall('日本', attrs.get('address')):
                raise ValidationError('出版社地址不能在日本')
            return attrs
    
    • 1
    • 2
    • 3
    • 4
    • 5

    四、序列化类ModelSerializer的使用

    modelSerializer是model与serializer的结合,在ModelSerializer中我们只需要配置好对应的字段和其参数即可,不需要重写update和create方法,ModeSerializer会自动完成增删改查操作。

    models.py

    class Book(models.Model):
        bid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
        authors = models.ManyToManyField(to='Author')
    
        def __str__(self):
            return self.name
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ModelSerializer序列化器

    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book # 此处设置ModelSerializer所关联的表
            # 此处有俩种设置方法
            fields = '__all__'  #方法1使用__all__会自动匹配models中的所有字段
            fields = ['bid', 'name', 'price', 'publish', 'authors', 'publish_read', 'authors_read'] #方法2使用列表的形式将需要对应的字段填入
            extra_kwargs = {
                'bid': {'read_only':True},
                'publish': {'write_only': True},
                'authors': {'write_only': True},
            } # 对自动对应的字段进行Serializer进行参数设置,此时的Serializer字段名与models中一致
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    针对于外键字段可以使用三种方式进行反序列化(序列化由ModelSerializer自动完成)
    第一种,构建虚拟字段为反序列化提供外键字段的查询结果(此方法不推荐)

    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book # 此处设置ModelSerializer所关联的表
            # 此处有俩种设置方法
            fields = '__all__'  #方法1使用__all__会自动匹配models中的所有字段,之后再新建虚拟字段
            fields = ['bid', 'name', 'price', 'publish', 'authors''publish_read', 'authors_read'] #方法2使用列表的形式将需要对应的字段填入包括虚拟字段,之后再对虚拟字段进行重新设置
            # fields选择一种即可
            extra_kwargs = {
                'bid': {'read_only':True}, #反序列化时主键一般都会设置read_only
            } # 对自动对应的字段进行Serializer进行参数设置,此时的Serializer字段名与models中一致
    
    	#在从此处创建虚拟字段,注意虚拟字段为class BookSerializer的属性(注意缩进)
    	publish_read = serializers.SerializerMethodField(read_only=True) #虚拟字段名可随意设置,不要忘记设置read_only
    	authors_read = serializers.SerializerMethodField(read_only=True)
    
    	#虚拟字段设置完毕后需要生成对应虚拟字段取值方法
    	def get_publish_read(self, book): # 此处方法名必须为get_虚拟字段名,参数self为serializer类,book可以自由设置名称该参数为对应的表对象
    		return book.publish.name #返回值依据外键关系来获取最好为query_set,一对多时需要返回query_set,一对一是也得返回query_set区别是一对一的query_set中只有一个字典
    
    	# 针对于多对多字段需要循环处理
    	def get_authors_read(self, book):# 由于是多对多关系此时的book为一个query_set其中包含多个表对象
           authors_list = []
           for author in book.authors.all():
               authors_list.append({'aid':author.pk, 'name':author.name, 'age':author.age, 'address':author.author_detail.address})
           return authors_list
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    第二种拔插式虚拟字段设置

    ModelSerializer序列化器:

    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = ['bid', 'name', 'price', 'publish', 'authors', 'publish_read', 'authors_read'] #此处需要将方法名与虚拟字段名对应起来,不可以使用__all__
            extra_kwargs = {
                'bid': {'read_only':True},
                'publish': {'write_only': True},
                'authors': {'write_only': True},
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    models模型:

    class Book(models.Model):
        bid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
        authors = models.ManyToManyField(to='Author')
    
        def __str__(self):
            return self.name
            
    	@property # 当fields选择第一种是需要添加该装饰器 装饰器作用是将类方法变为类属性
        def publish_read(self):
            return {'name':self.publish.name,'email':self.publish.email}
    	
    	@property
        def authors_read(self):
            authors_read=[]
            for author in self.authors.all():
                authors_read.append({'name':author.name,'address':author.author_detail.address})
            return authors_read
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    第三种设置连表深度
    连表查询深度:
    就是连表次数的设置
    例如:
    作者表与出版社表为一对多关系,从作者表可以连表查询到对应的出版社信息 此时深度为1
    出版社表与图书表为一对多关系,从出版社连表查询对应的图书,此时深度为2
    …后续按照此进行

    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = ['bid', 'name', 'price', 'publish', 'authors']
            depth = 1 # 官方建议不要超过10,实际上最好不要超过3
            extra_kwargs = {
                'bid': {'read_only':True},
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    9.3.5网络原理(应用层HTTP/HTTPS)
    Android 接入腾讯IM即时通信(详细图文)
    QT进阶---------pro项目文件中的常用命令 (第三天)
    基于STM32与ESP8266的太空人WiFi天气时钟(代码开源)
    解决Tomcat中文乱码问题
    Java多并发(一)| 并发机制的底层原理(内存模型、重排序)
    [管理与领导-125]:一个IT人的思考:职场中、人际交往中,不要为他人的不良行为和言语买单,不要让自己的情绪被外界影响或掌控。
    docker搭建minio服务器,解决内网穿透后外网无法访问问题
    测试22222
    [极客大挑战 2020]
  • 原文地址:https://blog.csdn.net/kdq18486588014/article/details/125296451