Django Rest Framework:在通过ModelViewSet创建对象时,按ID指定OneToOneField

时间:2016-07-19 22:16:18

标签: python django django-rest-framework

我在通过ID创建具有OneToOneField引用的对象时遇到了一些问题。我的代码示例:

models.py

class Person(models.Model):
    name = models.CharField(length=50)


class ExtraInfo(models.Model):
    person = models.OneToOneField(
        Person,
        related_name='+',
        primary_key=True,
        on_delete=models.CASCADE
    )
    info = models.CharField(length=50)

serializers.py

class ExtraInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.ExtraInfo

views.py

class ExtraInfoView(viewsets.ModelViewSet):
    queryset = models.ExtraInfo.objects.all()
    serializer_class = serializers.ExtraInfoSerializer

urls.py

...
api_router = DefaultRouter()
api_router.register(r'extrainfo', ExtraInfoView)

url_patterns = [
    url(r'/', include(api_router.urls))
]
...

现在,无论何时我做GET / extrainfo /我都会得到以下内容:

{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "person": 1,
            "info": "foo"
        },
        {
            "person": 2,
            "info": "bar"
        }
    ]
}

所以这一切都很好 - 正是我所期待的。当我尝试创建一些ExtraInfo时出现问题,当我使用诸如以下的正文POST到/ extrainfo /时:

{
    "person": 3,
    "info": "blah"
}

我收到以下错误:

ValueError: Cannot assign "3": "ExtraInfo.person" must be a "Person" instance.

所以我理解它的含义 - 如果我在定制的代码中这样做,我会想做像ExtraInfo.objects.create(person_id = 3,info =“blah”)这样的事情。我只是无法弄清楚如何让它像我想要的那样。

我看一下this answer,我无法弄清楚我哪里出错了。我似乎可以通过将它添加到我的序列化器来解决它:

def create(self, validated_data):
    validated_data['person_id'] = validated_data['person']
    del validated_data['person']
    return super(ExtraInfoSerializer, self).create(validated_data)

但这似乎不是最好的方法。我觉得我要么错过了一些小的东西,要么基本上误解了一些东西,但无论哪种方式我都觉得奇怪的是它将序列化为GET的主键但不会在POST中使用它。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

序列化程序期望person成为模型实例,因此您可以这样做:

{
    "person": Person.objects.get(pk=3),
    "info": "blah"
}

在视图中,您将获得相关模型实例的第一个表示形式,这是其主键。您还可以通过在序列化程序中指定depth参数来获取完整的模型实例。像:

class ExtraInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.ExtraInfo
        depth = 1