如何在DRF中正确序列化一对多关系

2 投票
1 回答
596 浏览
提问于 2025-04-18 09:23

我一直在尝试使用DRF(Django REST框架)来序列化和反序列化一些数据,但我不太确定哪里出了问题。


以下是我的模型:

from django.db import models

class FooA(models.Model):
    propA = models.CharField(max_length=30)

class FooB(models.Model):
    propB = models.CharField(max_lenght=30)
    propC = models.ForeignKey(FooC, related_name='fooBs')

class FooC(models.Model):
    propC = models.CharField(max_lenght=30)
    fooAs = models.ManyToMany(FooA, null=True, blank=True)


以下是我的序列化器:

from rest_framework import serializers
from myModule import models

class FooASerializer(serializers.ModelSerializer):
    class Meta:
        model = models.FooA
        fields = ('propA',)

class FooBSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.FooB
        fields = ('propB',)

class FooCSerializer(serializers.ModelSerializer):
    fooBs = FooBSerializer(many=True)
    fooAs = FooASerializer(many=True, required=False)

    class Meta:
        model = models.FooC
        fields = ('fooAs', 'fooBs',)


这是我的“视图”:

from rest_framework import generics
from .serializers import FooCSerializer
from .models import FooC

class FooCList(generics.ListCreateAPIView):
    model = FooC
    serializer_class = FooCSerializer


最后,这是我的路由设置:

from django.conf.urls import patterns, url, include
from .views import FooCList

urlpatterns = patterns('',
    url(r'^foocs/', FooCList.as_view())
)


我想做的是通过管理员界面创建一些数据,然后去DRF的API浏览器,复制一个FooC对象的JSON,稍微修改一下,测试能否成功将其反序列化为FooC对象。

这是我所做的:

>>> from rest_framework.compat import BytesIO
>>> from rest_framework.parsers import JSONParser
>>> from myApp.serializers import FooCSerializer
>>>
>>> content = '<slightly modified JSON copied from the DRF api browser>'
>>> stream = BytesIO(content)
>>> data = JSONParser().parse(stream)
>>> serializer = FooCSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.save()
ValueError: Cannot add "<FooA: fooA>": instance is on database "default", value is on database "None"


注意,它确实在我的数据库中创建了一个新的FooC实例,但并没有创建它的“嵌套”类(也就是FooC有关系的类)。


所以我有几个问题:

1) 这是预期的结果吗? 我原本希望它能“级联”创建所有相关的内容。

2) 如果这是设计使然,我在构建客户端时应该怎么做? 我的意思是,我原本期待能打开一个表单,在同一个表单中创建FooC及其所有相关实例。

谢谢大家!

1 个回答

0

简短回答:

1) 是的。

2) 有一些可能的解决办法。

为了让你明白我为什么对第一个问题回答“是”,我建议你去看看这里的解释,作者是DRF的创始人Tom Christie,链接在这里:https://groups.google.com/forum/#!msg/django-rest-framework/vCl2I_EzJnE/qwRdIdxiUe4J

至于解决办法,你可以选择:

1) 使用pre_save方法,在一个循环中创建你的嵌套对象,然后把它们的主键(PK)添加到当前的FooC实例中。

2) 为你的嵌套类创建一个视图,然后从那个视图调用方法,传入你请求中的相应数据。

希望这对你有帮助 :)

撰写回答