如何使用Django Rest Framework包含相关的模型字段?


153

假设我们有以下模型:

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
        }, 
    ]
},

这可能吗?如果是这样,怎么办?这是一个坏主意吗?

Answers:


242

最简单的方法是使用depth参数

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参数来指定用作字段源的属性。我们可以通过使用模型上的related_name选项source来确保teachers属性存在,从而删除参数。Teacherclassroom = models.ForeignKey(Classroom, related_name='teachers')

要记住的一件事是,嵌套的序列化程序当前不支持写操作。对于可写表示形式,应使用常规的平面表示形式,例如pk或超链接。


当我尝试第一个解决方案时,我没有收到老师,但是我确实收到了课堂父级的实例(此示例未显示)。在第二个解决方案中,我收到一个错误-“'Classroom'对象没有属性'teachers'”。我想念什么吗?
Chaz 2013年

1
@Chaz更新了答案,以说明depth在这种情况下为什么不执行所需的操作,并说明您看到的异常以及如何处理该异常。
克里斯蒂

1
我是个白痴,打错了服务器。它肯定适用于许多关系。
yellottyellott

15
嵌套序列化器很棒!我必须这样做,并且正在使用DRF 3.1.0。我必须many=True像这样包括在内...TeacherSerializer(source='teacher_set', many=True)。否则,我将收到以下错误:The serializer field might be named incorrectly and not match any attribute or key on the 'RelatedManager' instance. Original exception text was: 'RelatedManager' object has no attribute 'type'.
Karthic Raghupathi 2015年

2
..._set默认情况下,ForeignKey的背面将被命名。请参阅Django文档了解更多详情:docs.djangoproject.com/en/1.10/ref/models/relations/...
汤姆·克里斯蒂

36

谢谢@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",)

2

这也可以通过使用打包为drf-flex-fields的非常方便的dandy django来完成。我们使用它,它非常棒。您只需安装它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"})}

然后,将其添加?expand=teacher_set到您的URL中,并返回扩展的响应。希望有一天能对某人有所帮助。干杯!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.