【问题标题】:Django rest framework one to one relationDjango rest框架一对一关系
【发布时间】:2015-10-30 22:50:57
【问题描述】:

所以我有以下模型:

class A(models.Model):
  name = models.CharField()
  age = models.SmallIntergerField()

class B(models.Model):
  a = models.OneToOneField(A)
  salary = model.IntergerField()

现在我想为这两个创建一个休息端点,因为它们是一对一的。所以我想跟着get

{
  url: 'http://localhost/customs/1/',
  name: 'abc',
  age: 24,
  salary: 10000
}

同样,我也想创建记录和更新。请让我知道如何在 django rest framework 3 中实现这一点。

【问题讨论】:

    标签: python django rest django-rest-framework


    【解决方案1】:

    我知道这是一篇旧帖子,但经过一些研究和阅读Django Rest Framework documentation,我发现了这个 所以快速搜索一下,我发现您可以使用“related_name”参数进行反向关系,如here 所述

    ModelSerializerHyperlinkedModelSerializer 类不会自动包含反向关系。要包含反向关系,您必须将其显式添加到字段列表中。

    例如:

        class AlbumSerializer(serializers.ModelSerializer):
            class Meta:
            fields = ['tracks', ...]
    

    您通常需要确保为关系设置了适当的 related_name 参数,您可以将其用作字段名称。

    例如:

        class Track(models.Model):
            album = models.ForeignKey(Album, related_name='tracks', 
                    on_delete=models.CASCADE)
         ...
    

    如果您没有为反向关系设置相关名称,则需要在fields 参数中使用自动生成的related name

    例如:

        class AlbumSerializer(serializers.ModelSerializer):
           
            class Meta:
                fields = ['track_set', ...]
    

    另外,请参阅reverse relationships 上的 Django 文档了解更多详细信息。

    【讨论】:

      【解决方案2】:

      我刚刚遇到了同样的问题,让响应结构减少与底层模型结构的联系确实很有用。这是我的看法:

      阅读很容易

      Serializer fields有一个source参数,可以带点名来遍历属性。

      class ABSerializer(serializers.ModelSerializer):
      
          class Meta:
              model = A
              fields = ['name', 'age', 'salary']
      
          salary = serializer.IntegerField(source='b.salary') # this is your related_name
      

      写作是……没有官方支持

      经过验证的数据将显示嵌套结构,并且标准的创建和更新方法会在尝试将数据字典分配给 OneToOneField 时阻塞。 好消息是您可以通过覆盖 create and update 方法来解决它。这是一个更新示例:

      class ABSerializer(serializers.ModelSerializer):
      
          class Meta:
              model = A
              fields = ['name', 'age', 'salary']
              related_fields = ['b']
      
          salary = serializer.IntegerField(source='b.salary') # this is your related_name
      
          def update(self, instance, validated_data):
              # Handle related objects
              for related_obj_name in self.Meta.related_fields:
      
                  # Validated data will show the nested structure
                  data = validated_data.pop(related_obj_name)
                  related_instance = getattr(instance, related_obj_name)
      
                  # Same as default update implementation
                  for attr_name, value in data.items():
                      setattr(related_instance, attr_name, value)
                  related_instance.save()
              return super(ABSerializer,self).update(instance, validated_data)
      

      当然,这个例子非常简单,不做任何异常处理,也不能处理嵌套更深的对象……但你明白了。

      另一种选择

      您也可以create a read-write flavor of SerializerMethodField,它会同时考虑getter 和setter,但最终可能会变得更加冗长。

      希望有帮助!

      【讨论】:

      • 我更喜欢覆盖更新方法并显式获取经过验证的数据,因此不暗示处理“自动”错误(当然以“更多代码”为代价)。在示例中instance.b.salary = validated_data.get('b', {}).get('salary', '$1000000')
      猜你喜欢
      • 2017-06-23
      • 1970-01-01
      • 1970-01-01
      • 2014-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      相关资源
      最近更新 更多