Django rest框架一对一关系

Posted

技术标签:

【中文标题】Django rest框架一对一关系【英文标题】:Django rest framework one to one relation 【发布时间】: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 中实现这一点。

【问题讨论】:

【参考方案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')

以上是关于Django rest框架一对一关系的主要内容,如果未能解决你的问题,请参考以下文章

如何使用模型序列化器在 django-rest 中序列化一对多关系?

web框架开发-Django模型层-多表操作

Django.rest_framework:如何序列化一对多?

第六模块:WEB框架开发 第1章·Django框架开发50~100

Django框架(模型层:多表查询)

Django下orm学习 一对多