【问题标题】:How to save nested Backbone models with Django REST Framework如何使用 Django REST Framework 保存嵌套的 Backbone 模型
【发布时间】:2017-05-22 05:04:14
【问题描述】:

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

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

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

我已验证:

  • 为创建相关项目而发送的 ID 实际上与保存父项目后在done() 中返回的 ID 相同

  • 如果我在创建子项之前添加延迟,我可以检查数据库并验证父项确实已创建并保存到数据库中

  • 如果我在创建子项之前添加足够长的延迟(约 15 秒),则不会产生错误

由于 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。

【问题讨论】:

    标签: javascript python django backbone.js django-rest-framework


    【解决方案1】:

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

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

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

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

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

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

    后端应该返回:

    {
        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 &lt;- 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
    

    【讨论】:

    • 谢谢!这似乎是一个很好的替代解决方案。我仍然对为什么会发生这种情况感到困惑,因为当我在保存 Child 之前添加 5 秒延迟并检查数据库中的 Parent 表时,新的 Parent 在那里,但是保存 Child 仍然失败,好像不存在这样的父级。
    • @ZacharyBlackwood 很难说为什么会发生这种情况,可能是某个地方的配置或 Django 优化,它在实际保存之前做出响应。将整个保存放入单个请求将大大简化调试。此外,对 SO 的最佳感谢是赞成票;)
    猜你喜欢
    • 2015-05-23
    • 1970-01-01
    • 1970-01-01
    • 2019-06-02
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多