跳转至

REST framework入坑(5)-模型类序列化器

如果想为Django存在的模型类快速创建序列化器,可以使用DRF框架封装好的ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类

  • 基于模型类的字段条件创建约束
  • 自动生成序列化器(serializer)
  • 内部已经封装了createupdate方法,序列化器对象在调用save()方法时,会自动对数据库进行操作

1. 基础定义

# 继承自serializers.ModelSerializer
class StudentInfoSerializer(serializers.ModelSerializer)
    class Meta:
        model = StudentInfo # 指定要依据的模型类
        fields = '__all__' # 设置全部字段自动生成

2. 自定义过滤字段

  • 使用fields来明确字段, 可以写明具体哪些字段
# 继承自serializers.ModelSerializer
class StudentInfoSerializer(serializers.ModelSerializer)
    class Meta:
        model = StudentInfo # 指定要依据的模型类
        fields = ['id', 'name'] # 列表中设置指定要生成的字段
  • 使用exclude可以明确排除掉哪些字段
# 继承自serializers.ModelSerializer
class StudentInfoSerializer(serializers.ModelSerializer)
    class Meta:
        model = StudentInfo # 指定要依据的模型类
        exclude = ['info'] # 指定哪些字段不需要自动生成
  • 可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
# 继承自serializers.ModelSerializer
class StudentInfoSerializer(serializers.ModelSerializer)
    class Meta:
        model = StudentInfo # 指定要依据的模型类
        fields = '__all__' # 自定生成全部字段
        ead_only_fields = ['id', 'name'] # 指定列表中的字段仅用于序列化操作

3. 添加额外约束

extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

# 继承自serializers.ModelSerializer
class StudentInfoSerializer(serializers.ModelSerializer)
    class Meta:
        model = StudentInfo # 指定要依据的模型类
        fields = '__all__' # 设置全部字段自动生成
        extra_kwargs  = {
        name: { # 给name字段设置额外的约束
            'min_value': 0, # 设置最小的长度
            'required': True # 设置是否必传
            }
        info: { # 同上
            'min_value': 0,
            'required': True
            }
        }

4. 使用SerializerMethodField 优化

  • 数据用例
# 班级模型类
class ClassInfo(models.Model):
    name = models.CharField(max_length=20, verbose_name='班级名称')
    Info = models.CharField(max_length=20, verbose_name='班级信息')

    class Meta:
        db_table = 'class'
    def __str__(self):
        return self.name

# 学生模型类
class StudentInfo(models.Model):
    name = models.CharField(max_length=20, verbose_name='姓名')
    clsinfo = models.ForeignKey(ClassInfo, related_name='cls_stu)

    class Meta:
        db_table = 'student'
    def __str__(self):
        return self.name
  • 那么在 Django REST framework 我们通常按下面的方式定义 Serializer 类. 在 ClassInfo 类中增加一个属性 cls_stu(student外键到class的别名) 来保存当前 class 对象所有的学生集合. 但是此时有个问题如果此 Class 对象所拥有的 Student 比较多, 此时就会影响性能. 比如:
# 班级序列化器
class ClassSerializer(serializers.ModelSerializer):
    cls_stu = serializers.PrimaryKeyRelatedField(many=True, required=False, read_only=True)

    class Meta:
        model = Article
        fields = ('id', 'name', 'info', 'cls_stu')

# 学生序列化器
class StudentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = ('id', 'name', 'clsinfo')
  • 但是这样会出现一个问题: 这样序列化 Class 对象的时候会把 所有与 Class 对象关联的 student 对象的也序列化起来,就算是我们用 IntegerField 或者 StringRelatedField 那也会序列化很多用户的信息
  • 其实在很多时候我们并不需要在查询 Class 对象的时候查询所拥有的 Student 对象,很多时候我们只是需要一个 Class 所拥有 Student 对象的总数就可以了,如果有需要再去查询 Student 列表详细。此时我们就可以使用 Django REST framework 提供的 SerializerMethodField 来实现这个目的
# 班级序列化器
class ClassSerializer(serializers.ModelSerializer):
     get_cls_stu_count = serializers.SerializerMethodField()

    class Meta:
        model = Article
        fields = ('id', 'name', 'info', 'get_cls_stu_count')
    def get_cls_stu_count(self, obj):
        return obj.cls_stu.all().count()


# 学生序列化器
class StudentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = ('id', 'name', 'clsinfo')
  1. 首先在 ClassSerializer 中去除 cls_stu 属性
  2. 然后在 ClassSerializer 中增加一个属性 get_cls_stu_count, 并把这个属性添加到 Meta 的 fields 列表里
  3. 添加一个 get_cls_stu_count 方法,这个方法的命名规则就是在上面声明的属性前面加上个 'get_' 前缀,并接受一个 obj 参数,这个 obj 参数就是当前的 ClassInfo 对象实例。