【问题标题】:How do I include related model fields using Django Rest Framework?如何使用 Django Rest Framework 包含相关的模型字段?
【发布时间】:2021-12-31 03:13:02
【问题描述】:

假设我们有以下模型:

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

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

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    最简单的方法是使用the depth argument

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

    但是,这将只包括正向关系的关系,在这种情况下,这并不是您所需要的,因为教师字段是反向关系。

    如果您有更复杂的要求(例如,包含反向关系、嵌套某些字段但不嵌套其他字段或仅嵌套特定的字段子集),您可以nest serializers,例如...

    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 参数,而是通过使用Teacher 模型上的related_name 选项来确保teachers 属性存在,即。 classroom = models.ForeignKey(Classroom, related_name='teachers')

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

    【讨论】:

    • @Chaz 更新了答案以解释为什么 depth 在这种情况下不会做你需要的事情,并解释你看到的异常以及如何处理它。
    • 我是个白痴,打错了服务器。它绝对适用于多对多的关系。
    • 嵌套序列化程序很棒!我必须这样做并且使用的是 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'.
    • 嗨@TomChristie,感谢您的回答。我自己也在努力解决这个问题,但我不明白的一件事是_set 来自teachers = TeacherSerializer(source='teacher_set')。我尝试搜索 DRF 文档但一无所获。有什么提示吗?
    • ForeignKey 的反面默认命名为..._set。有关详细信息,请参阅 Django 文档:docs.djangoproject.com/en/1.10/ref/models/relations/…
    【解决方案2】:

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

    【讨论】:

    • 要过滤怎么办,teacher_set
    • 您可以在TeacherSerializer中添加一个list_serializer_class,并通过覆盖list_serializer_classto_representation函数来添加过滤逻辑。
    【解决方案3】:

    这也可以通过使用名为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 添加到您的网址,它会返回一个扩展的响应。 希望有一天这对某人有所帮助。干杯!

    【讨论】:

      【解决方案4】:

      感谢@TomChristie 和@Paolo

      我想澄清一下,下面的代码可以正常工作,但人们必须记住将 related_name="teacher_set" 属性添加到模型教师。在这种情况下,这里是完整的代码:

      models.py

      ​​>
      class Classroom(models.Model):
          room_number = [...]
      
      class Teacher(models.Model):
          name = [...]
          tenure = [...]
          classroom = models.ForeignKey(Classroom, related_name='teacher_set')
      

      注意:related_name='teacher_set'classroom 字段。

      serializers.py

      ​​>
      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",)
      

      【讨论】:

        猜你喜欢
        • 2013-01-12
        • 2022-06-14
        • 1970-01-01
        • 2016-12-18
        • 2015-01-17
        • 2021-12-24
        • 2018-11-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多