• 12 ModelSerializer组件


    模型类序列化器ModelSerializer

    如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

    ModelSerializer与常规的Serializer相同,但提供了:

    • 基于模型类自动生成一系列字段
    • 基于模型类自动为Serializer生成validators,比如unique_together
    • 包含默认的create()和update()的实现

    1. 定义

    比如我们创建一个BookInfoSerializer:

    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            fields = '__all__'
    
    • model 指明参照哪个模型类
    • fields 指明为模型类的哪些字段生成

    我们可以在python manage.py shell中查看自动生成的BookInfoSerializer的具体实现

    >>> from booktest.serializers import BookInfoSerializer
    >>> serializer = BookInfoSerializer()
    >>> serializer
    BookInfoSerializer():
        id = IntegerField(label='ID', read_only=True)
        btitle = CharField(label='名称', max_length=20)
        bpub_date = DateField(allow_null=True, label='发布日期', required=False)
        bread = IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)
        bcomment = IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False)
        image = ImageField(allow_null=True, label='图片', max_length=100, required=False)
    

    2. 指定字段

    1. 使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,如
    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date')
    
    1. 使用exclude可以明确排除掉哪些字段
    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            exclude = ('image',)
    
    1. 显示指明字段,如:
    class HeroInfoSerializer(serializers.ModelSerializer):
        hbook = BookInfoSerializer()
    
        class Meta:
            model = HeroInfo
            fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')
    
    1. 指明只读字段

    可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段

    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
            read_only_fields = ('id', 'bread', 'bcomment')
    

    3. 添加额外参数

    我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

    class BookInfoSerializer(serializers.ModelSerializer):
        """图书数据序列化器"""
        class Meta:
            model = BookInfo
            fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
            extra_kwargs = {
                'bread': {'min_value': 0, 'required': True},
                'bcomment': {'min_value': 0, 'required': True},
            }
    

    基于 Serializer组件的model、urls、views使用serializers.ModelSerializer重写

    4. 序列化

    class BookInfoModelSerializer(serializers.ModelSerializer):
        # 1.还可以自定义设置序列化字段,但是必须在fields中声明,在fields中写publish_address
        # 出版社显示名称,而不是0,1。。。
        publish_address = serializers.CharField(source='get_publisher_display', required=False)  # 找到对应中文
    
        # 图片显示全路径
        image_path = serializers.SerializerMethodField()
    
        def get_image_path(self, obj):
            # settings.MEDIA_URL: 自己配置的 /media/,给后面高级序列化与视图类准备的
            # obj.icon不能直接作为数据返回,因为内容虽然是字符串,但是类型是ImageFieldFile类型
            return '%s%s%s' % (r'http://127.0.0.1:8000', settings.MEDIA_URL, str(obj.image))
    
        # 自定义虚拟阅读量,原基础增加10
        fictitious_bread = serializers.SerializerMethodField()
    
        def get_fictitious_bread(self, obj):
            return obj.bread + 10
    
        class Meta:
            # 序列化关联的model类
            model = models.BookInfo
    
            # 参与序列化的字段
            fields = (
                'id', 'pwd', 'publisher', 'publish_address', 'btitle', 'bpub_date', 'created_time', 'bread',
                'fictitious_bread', 'bcomment', 'image', 'image_path')
    
            # 指明只读字段,即仅用于序列化输出的字段
            read_only_fields = ('publisher_name', 'fictitious_bread', 'image_path')
    

    5. 反序列化

    class BookInfoModelDeSerializer(serializers.ModelSerializer):
        pwd = serializers.CharField(label='密码', required=True)
        publisher = serializers.IntegerField(label='出版社', required=False)
        btitle = serializers.CharField(label='名称', max_length=20)
        bpub_date = serializers.DateField(label='发布日期', required=False)
        created_time = serializers.DateTimeField(label='创建时间', required=False)
        bread = serializers.IntegerField(label='阅读量', required=True)
        bcomment = serializers.IntegerField(label='评论量', required=True)
        image = serializers.ImageField(label='图片', required=False)
    
        # 自定义有校验规则的反序列化字段,例如确认密码字段re_pwd
        re_pwd = serializers.CharField(required=True)
    
        class Meta:
            model = models.BookInfo
            # 没有默认值的字段必须序列化,为其传值
            fields = ('pwd', 're_pwd', 'publisher', 'btitle', 'bpub_date', 'created_time', 'bread', 'bcomment', 'image')
    
        # 局部钩子:validate_要校验的字段名(self, 当前要校验字段的值)
        # 校验规则:校验通过返回原值,校验失败,抛出异常
        def validate_btitle(self, value):
            if 'django' not in value.lower():
                raise exceptions.ValidationError('validate_btitle-图书不是关于Django的')
            return value
    
        # 全局钩子:validate(self, 通过系统与局部钩子校验之后的所有数据)
        def validate(self, attrs):  # attrs是字典格式
            pwd = attrs.get('pwd')
            re_pwd = attrs.pop('re_pwd')  # 因为re_pwd不需要存入数据库,所以在全局钩子校验中删除掉这个字段
            print(re_pwd)
            bread = attrs['bread']
            bcomment = attrs['bcomment']
            if pwd != re_pwd:
                raise exceptions.ValidationError({'pwd&re_pwd': '两次密码不一致'})
            if bread < bcomment:
                raise serializers.ValidationError('阅读量小于评论量')
            return attrs
    
        # 注意:ModelSerializer类已经帮我们实现了 create 与 update 方法,不需要写create就能创建
    

    6 序列化与反序列化整合

    序列化层:api/serializers.py

    class BookModelSerializer(serializers.ModelSerializer):
        pwd = serializers.CharField(label='密码', required=True)
        publisher = serializers.IntegerField(label='出版社', required=False)
        btitle = serializers.CharField(label='名称', max_length=20)
        bpub_date = serializers.DateField(label='发布日期', required=False)
        created_time = serializers.DateTimeField(label='创建时间', required=False)
        bread = serializers.IntegerField(label='阅读量', required=True)
        bcomment = serializers.IntegerField(label='评论量', required=True)
        image = serializers.ImageField(label='图片', required=False)
    
        # 序列化自定义字段
        # 出版社显示名称,而不是0,1。。。
        publisher_name = serializers.CharField(source='get_publisher_display', required=False)  # 找到对应中文
        # 图片显示全路径
        image_path = serializers.SerializerMethodField()
        # 自定义虚拟阅读量,原基础增加10
        fictitious_bread = serializers.SerializerMethodField()
    
        # 反序列化自定义字段
        re_pwd = serializers.CharField(required=True, write_only=True)
    
        class Meta:
            model = models.BookInfo
            fields = "__all__"
            # 只读字段
            read_only_fields = (
                'id', 'pwd',  'publisher', 'publisher_name', 'btitle', 'bpub_date', 'created_time', 'bread',
                'fictitious_bread', 'bcomment', 'image', 'image_path')
            extra_kwargs = {
                'pwd': {
                    'write_only': True
                },
                're_pwd': {
                    'write_only': True
                },
                'bpub_date': {
                    'write_only': True
                },
                'publisher': {
                    'write_only': True,
                },
    
                'img': {
                    'read_only': True,
                },
                'created_time': {
                    'read_only': True,
                },
                'publish_name': {
                    'read_only': True,
                }
            }
    
        def get_image_path(self, obj):
            # settings.MEDIA_URL: 自己配置的 /media/,给后面高级序列化与视图类准备的
            # obj.icon不能直接作为数据返回,因为内容虽然是字符串,但是类型是ImageFieldFile类型
            return '%s%s%s' % (r'http://127.0.0.1:8000', settings.MEDIA_URL, str(obj.image))
    
        def get_fictitious_bread(self, obj):
            return obj.bread + 10
    
        # 局部钩子:validate_要校验的字段名(self, 当前要校验字段的值)
        # 校验规则:校验通过返回原值,校验失败,抛出异常
        def validate_btitle(self, value):
            if 'django' not in value.lower():
                raise exceptions.ValidationError('validate_btitle-图书不是关于Django的')
            return value
    
        # 全局钩子:validate(self, 通过系统与局部钩子校验之后的所有数据)
        def validate(self, attrs):  # attrs是字典格式
            pwd = attrs.get('pwd')
            re_pwd = attrs.pop('re_pwd')  # 因为re_pwd不需要存入数据库,所以在全局钩子校验中删除掉这个字段
            print(re_pwd)
            bread = attrs['bread']
            bcomment = attrs['bcomment']
            if pwd != re_pwd:
                raise exceptions.ValidationError({'pwd&re_pwd': '两次密码不一致'})
            if bread < bcomment:
                raise serializers.ValidationError('阅读量小于评论量')
            return attrs
    
        # 注意:ModelSerializer类已经帮我们实现了 create 与 update 方法,不需要写create就能创建
    

    序列化层注意点:

    1) fields中设置所有序列化与反序列化字段
    2) extra_kwargs划分只序列化或只反序列化字段(一般我们把需要存入到数据库中的使用write_only(反序列化),只需要展示的就read_only(序列化),看需求设计)
        write_only:只反序列化
        read_only:只序列化
        自定义字段默认只序列化(read_only)
        如果字段没设置write_only或者read_only,那么该字段可以序列化和反序列化
    3) 设置反序列化所需的 系统、局部钩子、全局钩子 等校验规则
    

    7 ModelSerializer总结

    class BookSerializer(serializers.ModelSerializer):
        model字段或自定义字段
        
        class Meta:
            model = models.BookInfo   # 与BookInfo表对应
            # 使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段
            fields=('参与序列化和反序列的字段1','参与序列化和反序列的字段2')
            fields = "__all__"  
            
            # 使用exclude可以明确排除掉哪些字段
            exclude = ('image',)
            # 指明只读字段  通过read_only_fields指明只读字段,即仅用于序列化输出的字段
            read_only_fields = ('id', 'bread', 'bcomment')
            
            # 为ModelSerializer添加或修改原有的选项参数
            extra_kwargs = {
                
            }
        # 局部钩子:validate_要校验的字段名(self, 当前要校验字段的值)
        # 校验规则:校验通过返回原值,校验失败,抛出异常
        def validate_btitle(self, value):
            ....
            return value
        # 全局钩子:validate(self, 通过系统与局部钩子校验之后的所有数据)
        def validate(self, attrs):  # attrs是字典格式
            ...
            return attrs
    
  • 相关阅读:
    Linux基础命令总结
    在Linux服务器上配置phpMyAdmin
    nginx配置301重定向
    nginx服务器设置url的优雅链接
    nginx服务器绑定域名和设置根目录的方法
    VMware ESXi客户端连接控制台时提示"VMRC控制台连接已断开...正在尝试重新连接"的解决方法
    搭建Solr集群的推荐方案
    汉语-成语:少不更事
    汉语-成语:老成持重
    汉语-成语:少年老成
  • 原文地址:https://www.cnblogs.com/LYPZX/p/14075945.html
Copyright © 2020-2023  润新知