如何在Django Rest Framework中包含相关模型字段?

194 投票
4 回答
117457 浏览
提问于 2025-04-17 13:59

假设我们有一个这样的模型:

class Classroom(models.Model):
    room_number = [...]

class Teacher(models.Model):
    name = [...]
    tenure = [...]
    classroom = models.ForeignKey(Classroom)

假设我们希望得到的结果不是像ManyRelatedPrimaryKeyField函数那样的结果:

{
    "room_number": "42", 
    "teachers": [
        27, 
        24, 
        7
    ]
},

而是返回一个包含完整相关模型信息的结果,比如:

{
    "room_number": "42", 
    "teachers": [
        {
           'id': 27,
           'name': 'John',
           'tenure': True
        }, 
        {
           'id': 24,
           'name': 'Sally',
           'tenure': False
        }, 
    ]
},

这样做可能吗?如果可以的话,怎么做?这样做是不是个坏主意?

4 个回答

8

这可以通过一个非常好用的 Django 包来实现,叫做 drf-flex-fields。我们在用这个包,效果非常棒。你只需要安装它,方法是运行 pip install drf-flex-fields,然后把它放到你的序列化器里,添加 expandable_fields,就大功告成了(下面有示例)。这个包还允许你使用点号表示法来指定深层嵌套的关系。

from rest_flex_fields import FlexFieldsModelSerializer

class ClassroomSerializer(FlexFieldsModelSerializer):
    class Meta:
        model = Model
        fields = ("teacher_set",)
        expandable_fields = {"teacher_set": (TeacherSerializer, {"source": "teacher_set"})}

接着,你在你的 URL 后面加上 ?expand=teacher_set,这样就能返回一个扩展的响应了。希望这能在某一天帮助到某个人。干杯!

53

谢谢你,@TomChristie!!!

你帮了我很多忙!

我想稍微更新一下这个内容(因为我遇到了一个错误)

class TeacherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = ('id', 'name', 'tenure')

class ClassroomSerializer(serializers.ModelSerializer):
    teachers = TeacherSerializer(source='teacher_set', many=True)

    class Meta:
        model = Classroom
        field = ("teachers",)
294

最简单的方法是使用 深度参数

class ClassroomSerializer(serializers.ModelSerializer):
    class Meta:
        model = Classroom
        depth = 1

不过,这样做只会包含正向关系的数据,而在这个例子中,你需要的是反向关系的数据,因为教师字段是反向关系。

如果你有更复杂的需求(比如需要包含反向关系、嵌套某些字段但不嵌套其他字段,或者只嵌套特定的一部分字段),你可以 嵌套序列化器,例如...

class TeacherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Teacher
        fields = ('id', 'name', 'tenure')

class ClassroomSerializer(serializers.ModelSerializer):
    teachers = TeacherSerializer(source='teacher_set')

    class Meta:
        model = Classroom

注意,我们在序列化器字段上使用了 source 参数来指定用作字段来源的属性。我们也可以不使用 source 参数,而是通过在 Teacher 模型上使用 related_name 选项来确保 teachers 属性存在,比如 classroom = models.ForeignKey(Classroom, related_name='teachers')

需要记住的一点是,嵌套序列化器目前不支持写操作。如果需要可写的表示方式,应该使用常规的扁平表示,比如主键(pk)或超链接。

撰写回答