在 Django 中一次提交中执行多个 save() 的最佳方法

Posted

技术标签:

【中文标题】在 Django 中一次提交中执行多个 save() 的最佳方法【英文标题】:The best way to do multiple save() in one submit in Django 【发布时间】:2018-09-16 05:17:20 【问题描述】:

我是 Django 的新手,实际上是网络开发。找了好久,还没找到答案。

在我的项目中,当用户提交表单请求时,它会搜索一些网站,如果找到特定的图片,它会下载图片并返回下载链接。

目前我有两个模型:

    请求

    class Request(models.Model):
        create_time = models.DateTimeField('create time', auto_now_add=True)
        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET('unknown'))
        image_name = models.CharField(max_length=48)
        image = models.ForeignKey(Image, on_delete=models.SET('unknown'))
    

    图片

    class Image(models.Model):
        add_time = models.DateTimeField('add time', auto_now_add=True)
        image_source = models.CharField(max_length=48)
        image_size = models.CharField(max_length=48)
    

只是想知道在提交请求时将 save() 保存到模型的最佳方式是什么。我正在考虑的方法是:

选项 A:

    收到请求后,使用基本的 save() 到请求模型 信息 - 除了“图像 ID”(尚不可用),并设置 状态为“开始” 进行搜索,下载图片,然后 save() 到 图像模型 - 现在我有了“图像 ID” 使用“图像 ID”信息更新请求实例,并且 将状态更新为“成功”

选项 B:

    请求时立即搜索并下载图片 收到,并保存()到图像模型 - 现在我有了“图像 ID”

    Save() 到带有“图像 ID”的请求模型 - 这是一个新的 插入活动。

最好的方法是什么?或者还有其他更好的方法吗?

另外,在这种情况下使用 Django 的“事务”功能有什么建议吗?我不喜欢在我的小项目中使用它——只是不想让它变得太复杂。

【问题讨论】:

【参考方案1】:

我会选择选项 A,并且我强烈建议您重命名“请求”模型以不同的名称,例如:“SearchRequest”Request 在 django 世界中非常具体如果你给它添加一个新的上下文,你很快就会很困惑。

SearchRequest被触发时,您可以保存创建时间,STARTED中的状态,然后进行研究。在研究过程中可能会出现问题,因此最好将图像搜索包装在 try/except 上。然后,您可以使用FAILED 保存状态以及出现问题的原因。这回答了关于原子事务的问题,你不需要那个

另外一个建议,把图片的名字移到Image模型上,SearchRequest可以从相关图片中获取图片的名字。

对 SearchRequest 的改进是将状态保存为相关模型,以便您可以在搜索期间重建状态的变化。

class SearchRequestStatus(models.Model):
    create_time = models.DateTimeField('create time', auto_now_add=True)
    status = models.CharField(max_length=48)
    detail = models.CharField(max_length=256)
    search = models.ForeignKey(SearchRequest, on_delete=models.CASCADE, related_name='statuses')

此解决方案可以通过两种方式完成:

    您将状态的显式更改保存在相关字段中 手动创建一个新的 SearchRequestStatus 或..

    您将statusstatus_detail 保存在SearchRequest 和 保存信号将获取更改并自动创建一个 SearchRequestStatus 使用接收器。 (看: https://docs.djangoproject.com/en/2.1/topics/signals/)

    @receiver(signals.post_save, sender=SearchRequest, weak=False, dispatch_uid="_update_search_request_status_history") def _update_search_request_status_history(sender, instance, **kwargs): current_status = SearchRequest.objects.filter(search=instance).first() 如果不是 current_status 或 current_status.status != instance.status: SearchRequestStatus.objects.create(search=instance, status=instance.status, status_detail=instance.status_detail)

当然,您必须将字段添加到您的SearchRequest 模型中,并添加 STATUSES 元组来限制状态的选择

status = models.CharField(max_length=15, choices=STATUSES.items(), default=`STARTED`)
status_detail = models.CharField(max_length=80, null=True, blank=True)

【讨论】:

以上是关于在 Django 中一次提交中执行多个 save() 的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 中一次将多个对象添加到 ManyToMany 关系?

如何在 Prometheus 中一次调用执行多个查询

在 Mongoose 中一次执行多个查询

如何在 Firestore 中一次创建/更新多个文档

在 oracle 中一次捕获多个异常

在 django 管理面板中一次添加多条记录