如何使用 Django REST Framework 保存嵌套 Backbone 模型
How to save nested Backbone models with Django REST Framework
我正在尝试快速保存一系列由外键关联的项目。保存父项后,我在创建子项时使用父项返回的 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。
看起来第一个请求成功但尚未进入数据库的地方正在发生竞争条件,可能只是在此请求的线程中的缓存中。然后后续调用到达,创建另一个线程来处理它,但父 尚未真正 在数据库中,因此失败。
如何使用 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
我正在尝试快速保存一系列由外键关联的项目。保存父项后,我在创建子项时使用父项返回的 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。
看起来第一个请求成功但尚未进入数据库的地方正在发生竞争条件,可能只是在此请求的线程中的缓存中。然后后续调用到达,创建另一个线程来处理它,但父 尚未真正 在数据库中,因此失败。
如何使用 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