在 Django DRF 中一起更新多个资源
Update multiple resource together in Django DRF
假设我在 Django 中有两个模型:
class Inventory(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
added_by = models.ForeignKey(User, on_delete=models.SET("anonymous"),
blank=True, null=True)
name = models.CharField(max_length=100, unique=True)
nickname = models.CharField(max_length=100, blank=True, null=True)
class InventoryProperties(models.Model):
key = models.CharField(max_length=100)
value = models.CharField(max_length=100)
order = models.IntegerField()
item = models.ForeignKey(Inventory, on_delete=models.CASCADE, related_name='properties')
如果我想在同一页面(表单)的前端向它添加库存和一些属性怎么办。
那么我必须先保存库存项目,然后再保存属性。
正如我在 REST 中读到的那样,这不应该用一个资源来完成(因为这是一个不同的资源,所以现在我有 /inventory/:id/properties/):
How to handle updates in a REST API?
如果在保存属性的过程中出现问题怎么办?我无法轻松回滚已保存的库存项目,所以我最终得到了一个保存了一半的对象。
而且这在前端真的很难管理,因为如果在 属性 保存过程中发生一些错误,前端不应该再次保存库存。
似乎 InventoryProperties
实体如果没有它们的 Inventory
关系就永远不会使用。因此,您可以使用 JSONField
Inventory.propetries
而不是单独的实体。
class Inventory(models.Model):
props = models.JSONField(default=list)
name = models.CharField(max_length=100, unique=True)
class InventorySerializer(serializers.ModelSerializer):
class Meta:
model = Inventory
fields = ['name', 'props']
此序列化程序将在每次保存时重写所有 props in 1 SQL UPDATE 查询。作为奖励,您不需要支持 InventoryProperties.order
字段。
输入示例
{
"name": "inv1",
"props": [
{"key": "size", "value": 30},
{"key": "weight", "value": 16},
]
}
此外,您可以通过 key
添加访问属性的方法
class Inventory(models.Model):
def get_prop(self, key: str):
for prop in self.props:
if prop["key"] == key:
return prop["value"]
return None
如果你想添加 JSON 的验证,你可以使用 this 方法
对于这种情况,您可以使用 django 事务,如果您的事务块中发生任何错误,它将回滚您的数据库事务。像这样的东西-
from django.db import transaction
with transaction.atomic():
Inventory.objects.create(**kwargs)
InventoryProperties.objects.create(**kwargs)
在事务块中,如果保存 InventoryProperties 出现任何错误,那么 Inventory Table 将被回滚。
我的解决方案是我创建了一个单独的端点,我可以在其中同时更新嵌套模型和多个模型,同时还提供典型的 RESTful 端点。
此端点使用原子事务,因此如果业务逻辑出现任何问题,则不会提交任何内容。
假设我在 Django 中有两个模型:
class Inventory(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
added_by = models.ForeignKey(User, on_delete=models.SET("anonymous"),
blank=True, null=True)
name = models.CharField(max_length=100, unique=True)
nickname = models.CharField(max_length=100, blank=True, null=True)
class InventoryProperties(models.Model):
key = models.CharField(max_length=100)
value = models.CharField(max_length=100)
order = models.IntegerField()
item = models.ForeignKey(Inventory, on_delete=models.CASCADE, related_name='properties')
如果我想在同一页面(表单)的前端向它添加库存和一些属性怎么办。
那么我必须先保存库存项目,然后再保存属性。
正如我在 REST 中读到的那样,这不应该用一个资源来完成(因为这是一个不同的资源,所以现在我有 /inventory/:id/properties/): How to handle updates in a REST API?
如果在保存属性的过程中出现问题怎么办?我无法轻松回滚已保存的库存项目,所以我最终得到了一个保存了一半的对象。
而且这在前端真的很难管理,因为如果在 属性 保存过程中发生一些错误,前端不应该再次保存库存。
似乎 InventoryProperties
实体如果没有它们的 Inventory
关系就永远不会使用。因此,您可以使用 JSONField
Inventory.propetries
而不是单独的实体。
class Inventory(models.Model):
props = models.JSONField(default=list)
name = models.CharField(max_length=100, unique=True)
class InventorySerializer(serializers.ModelSerializer):
class Meta:
model = Inventory
fields = ['name', 'props']
此序列化程序将在每次保存时重写所有 props in 1 SQL UPDATE 查询。作为奖励,您不需要支持 InventoryProperties.order
字段。
输入示例
{
"name": "inv1",
"props": [
{"key": "size", "value": 30},
{"key": "weight", "value": 16},
]
}
此外,您可以通过 key
class Inventory(models.Model):
def get_prop(self, key: str):
for prop in self.props:
if prop["key"] == key:
return prop["value"]
return None
如果你想添加 JSON 的验证,你可以使用 this 方法
对于这种情况,您可以使用 django 事务,如果您的事务块中发生任何错误,它将回滚您的数据库事务。像这样的东西-
from django.db import transaction
with transaction.atomic():
Inventory.objects.create(**kwargs)
InventoryProperties.objects.create(**kwargs)
在事务块中,如果保存 InventoryProperties 出现任何错误,那么 Inventory Table 将被回滚。
我的解决方案是我创建了一个单独的端点,我可以在其中同时更新嵌套模型和多个模型,同时还提供典型的 RESTful 端点。 此端点使用原子事务,因此如果业务逻辑出现任何问题,则不会提交任何内容。