如何使用 Django REST Framework 保存嵌套 Backbone 模型

How to save nested Backbone models with Django REST Framework

我正在尝试快速保存一系列由外键关联的项目。保存父项后,我在创建子项时使用父项返回的 id。

这一次或两次有效,但在第二次或第三次时,我收到消息:

{"parent_id":["Invalid pk \"5063\" - object does not exist."]}

我已经确认:

由于 Backbone.js 前端似乎正在发送有效的 POST 请求,并且项目正在立即正确写入数据库,我认为这是一个 Django 问题。

Backbone.js代码

var i = 0;

function createNew() {
    var parent = ParentObjects.add({name: "New Parent Item"});
    parent.save().done(function(var attributes, stuff, stuff) {
        var id = attributes.id;
        var child = ChildObjects.add({name: "New Child Item", parent_id: id});
        child.save().done(function() {
            i++;
            if (i < 10) {
                createNew();
            }
        });
    });
}

Django Rest 框架代码

class Parent(Model):
    name = models.CharField(max_length=200)

class Child(Model):
    parent = models.ForeignKey(Parent, related_name="children")
    name = models.CharField(max_length=200)

class ParentSerializer(ModelSerializer):
    class Meta:
        model = Parent

class ChildSerializer(ModelSerializer):
    parent_id = serializers.PrimaryKeyRelatedField(
        source='parent',
        queryset=Parent.objects.all(),
    )

    class Meta:
        model = Child
        exclude = ('parent', )

class ChildViewSet(ModelViewSet):
    queryset = Child.objects.all()
    serializer_class = ChildSerializer

class ParentViewSet(ModelViewSet):
    queryset = Parent.objects.all()
    serializer_class = ParentSerializer

数据库是Postgresql。

看起来第一个请求成功但尚未进入数据库的地方正在发生竞争条件,可能只是在此请求的线程中的缓存中。然后后续调用到达,创建另一个线程来处理它,但父 尚未真正 在数据库中,因此失败。

如何使用 Backbone 保存嵌套模型?

Backbone 的经验法则是不要一个接一个地循环请求 API。

相反,将整个对象发送到 API。 外键是一个关系数据库的概念,你应该尽量避免在前端做database/backend工作。

例如,父项的 attributes 可用于同时创建父项及其子项:

ParentObjects.create({
    name: "New Parent Item",
    children: [
        { name: "New Child Item" }
    ]
});

后端应该return:

{
    id: "23",
    name: "New Parent Item",
    children: [
        { id: "35", name: "New Child Item", parent: "23" }
    ]
}

如何使用 Django REST Framework (DRF) 保存嵌套模型?

从第 3 版开始,DRF 提供 writable nested representation,因此它几乎可以直接使用上面的 Backbone 示例。您只需要为子模型字段提供一个序列化程序并覆盖 create 方法。

这是文档中的一个简单关系示例 User <- Profile:

class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer()

    class Meta:
        model = User
        fields = ('username', 'email', 'profile')

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        user = User.objects.create(**validated_data)
        Profile.objects.create(user=user, **profile_data)
        return user