美文网首页
14、Django_rest framework_ModelSe

14、Django_rest framework_ModelSe

作者: 猪儿打滚 | 来源:发表于2019-11-15 18:44 被阅读0次

一、进一步封装优化序列化器

  • 注意:更高一级的封装,代表着更少的代码,也代表着更低的可定制型
  • 要讲诉的方法,类似Django原生的ModelFormmodel的引用

二、ModelSerializer

  • ModelSerializer类能够让我们自动你创建一个具有对应模型类中,相对应字段的Serializer
  • ModelSerializer类直接继承了Serializer类,不同的是:
    1.它根据model模型的定义,自动生成默认字段。
    2.它自动生成序列化器的验证器,比如unique_together验证器。
    3.它实现了简单的.create()方法和.update()方法。
  • 声明一个ModelSerializer类,(用之前写好的序列化器示例,注释之前的类属性字段,修改成ModelSerializer类)
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        # 需要序列化的model类
        model = User

        # 序列化所有的字段
        # fields = '__all__'

        # 序列化指定字段
        # fields = ('name', 'password', 'email', 'sex')

        # 排除哪些字段不进行序列化
        exclude = ('email',)

注意:由于对应了model类的字段,会存在必填字段,所以fileds=__all__exclude慎重使用

  • 进入shell查看ModelSerializer类自动创建了哪些字段和验证器(fileds=__all__的)

    进入shell
  • 测试是否能添加成功:


    添加成功
2.1、明确指定字段

当觉得全自动的字段不满足需求时,可以通过在ModelSerializer类上显式声明字段,从而增加额外的字段或者重写默认的字段,就和在Serializer类一样的。
比如:

class UserSerializer(serializers.ModelSerializer):
    c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)

    class Meta:
        model = User
        fields = '__all__'
明确指定ctime
2.2、指定只读字段

当我们希望批量将某些字段指定为只读,而不是显式的逐一为每个字段添加read_only=True属性,这种情况就可以使用Metaread_only_fields选项。
该选项的值是字段名称所组成的列表或元组,并像下面这样声明:

class UserSerializer(serializers.ModelSerializer):
    c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)

    class Meta:
        model = User
        fields = '__all__'
        read_only_fields = ('sex', 'password')
批量指定只读

注意: 有一种特殊情况,其中一个只读字段是模型级别unique_together约束的一部分。在这种情况下,序列化器需要该字段的值才能验证约束,但也是不能由用户编辑的。
处理此问题的正确方法是在序列化器上显式指定该字段,同时提供read_only=True和default=…关键字参数。
这种情况的一个例子就是对于一个和其他标识符unique_together的当前认证的User是只读的。 在这种情况下可以像下面这样声明user字段:

user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
  • PrimaryKeyRelatedField处理反向关联关系/反向序列化
    比如说interfaces是projects的从表。此时的设计是:在创建interface时,前端会传递一个project_id,我们实际在创建interface时,是不会使用project_idproject_idinterfaces.modelprojects.model是一个反向关联关系。所以我们此时需要为它添加一个显示字段。
    interfaces/serialzers.py
from rest_framework import serializers

from projects.models import Projects
from interfaces.models import Interfaces


class InterfaceModelSerializer(serializers.ModelSerializer):
    # 从表指定输出主表外键输出的值
    project = serializers.StringRelatedField(label='所属项目', read_only=True)
    # 新增model不存在的字段,前端传递的是project_id,并且和project表是一个反向关联关系,所以需要添加一个显示字段
    project_id = serializers.PrimaryKeyRelatedField(queryset=Projects.objects.all(), write_only=True,
                                                    label='所属项目id', help_text='所属项目id')

    class Meta:
        model = Interfaces
        fields = ('id', 'name', 'tester', 'create_time', 'desc', 'project', 'project_id')

        extra_kwargs = {
            'create_time': {
                'read_only': True
            }
        }

    def create(self, validated_data):
        """
        前端传的是project_id,而对应的字段应该是project,所以需要处理下这里
        :param validated_data:
        :return:
        """
        project_id = validated_data.pop('project_id')
        validated_data['project'] = project_id
        interface_obj = super().create(validated_data)
        return interface_obj
2.3、添加关键字参数

可以通过使用extra_kwargs选项快捷地在字段上指定任意附加的关键字参数。这个选项是一个将具体字段名称当作键值的字典。

  • 用法:在给字段添加ModelSerializer无法自动添加的额外条件时使用
  • 注意:extra_kwargs的值是一个字段,里面的key需要和校验参数一致,否则出错(可看源码)
    例如:
class UserSerializer(serializers.ModelSerializer):
    c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)

    class Meta:
        model = User
        fields = '__all__'
        extra_kwargs = {
            # model的任意字段
            "name": {
                "write_only": True,  # 字段名别写错
                "error_messages": {  #  字段名别写错
                    "max_length": "用户名最多不能超过50个字符"
                }
            }
        }
添加关键字参数
2.4、添加序列化器自定义的校验
  • 直接复制粘贴过来,但是要注意,必须和class Meta平级
class UserSerializer(serializers.ModelSerializer):
    c_time = serializers.DateTimeField(label='创建时间', help_text='创建时间', read_only=True)

    class Meta:
        model = User
        fields = '__all__'
        extra_kwargs = {
            # model的任意字段
            "name": {
                "write_only": True,  # 字段名别写错
                "error_messages": {  #  字段名别写错
                    "max_length": "用户名最多不能超过50个字符"
                }
            }
        }

    # 自定义字段级别的验证
    def validate_name(self, value):
        """
        用户名需要以“用户”开头
        :return:
        """
        if not str(value).startswith('用户'):
            # 抛出erializers.ValidationError异常
            raise serializers.ValidationError(detail='用户名需要以用户两个字开头')
        # 返回一个验证过的数据
        else:
            return attrs

    # 自定义多个字段的组合验证规则
    def validate(self, attrs):
        """
        password和email必需含有“lzl”这三个字母
        :return:
        """
        if "lzl" not in attrs['password'] or "lzl" not in attrs['email']:
            raise serializers.ValidationError(detail='password和email必需含有“lzl”这三个字母')
        else:
            return attrs
2.5、views.py的修改
  • ModelSerializer类因为实现了简单的.create()方法和.update()方法。所以之前的views.py中的代码只需要把之前的Serializer类改成调用继承了ModelSerializer的类即可
2.6、指定外键序列化输出的值(从表指定主表外键)

主表:projcet
从表:interface
在interface副表中,外键是projcet
当使用ModelSerializer进行序列化时,默认会对project外键进行处理,默认生成的是PrimaryKeyRelatedField序列化器字段,序列化输出的是该interface对应的project表的id。
如果需要修改,那么需要显示处理:

from rest_framework import serializers

from interfaces.models import Interfaces
from projects.serializer import ProjectModelSerializer

class InterfaceModelSerializer(serializers.ModelSerializer):
    # 指定外键序列化输出内容(project是interface的外键字段)
    # 1、StringRelatedField:此字段会被序列化为关联对象字符串表达形式,也就是__str__方法的内容
    project = serializers.StringRelatedField(label='所属项目')
    # 2、SlugRelatedField:指定序列化返回的字段,比如下面序列化的结果是关联project表的leader字段的值
    project = serializers.SlugRelatedField(label='所属项目',  slug_field='leader')
    # 3、  指定返回关联的project序列化器(需要指定read_only,不然前端就需要输入一个project序列化器)
    project = ProjectModelSerializer((label='所属项目',  read_only=True)

    class Meta:
        model = Interfaces
        fields = '__all__'
2.6、指定外键序列化输出的值(主表指定从表)

主表中不会默认生成从表的关联字段,需要手动指定,并且字段名是从表名_set。其它方法和和在从表指定主表的一样。

class ProjectModelSerializer(serializers.ModelSerializer):
    #注意字段名,并且由于是从表,多的一方,要指定many=True
    interfaces_set = serializers.StringRelatedField(label='项目接口', many=True)
    class Meta:
        model = Interfaces
        fields = '__all__'

相关文章

网友评论

      本文标题:14、Django_rest framework_ModelSe

      本文链接:https://www.haomeiwen.com/subject/eqbsictx.html