首页 > 解决方案 > 在 Django 中使用原子事务处理模型的保存方法

问题描述

老实说,这个问题是不言自明的。我有 2 个相关的模型。它是这样的:

from django.db import IntegrityError, transaction

class Item(models.Model):
    total_score = models.IntegerField()

    def set_score(self):
         ...

class Review(models.Model):
    item = models.ForeignKey(Item, on_delete=models.CASCADE)
    score = models.IntegerField()

    def save(self, *args, **kwargs):
        try:
            with transaction.atomic():
                super(Review, self).save(*args, **kwargs)
                self.item.set_score()
        except IntegrityError:
            handle_exception()

基本上,每当保存评论时,其项目的分数都会使用set_score()方法更新其项目的分数。我将整个事情放在原子事务中,因为很明显,我不希望更新评论并且项目的分数保持未更新。这就像潜在错误的滋生地。无论如何,这是正确的方法吗?我觉得我无法在本地服务器上对此进行测试,因为不可能创建一个保存评论但不更新分数的错误。谢谢。

注意:我知道有更好的方法可以根据评论处理项目的分数。这不是问题的重点。为了解释我想要做什么,这是一个虚构的场景。所以,拜托,没有提到这一点的答案。

标签: django

解决方案


Yes, you could do it as you have mentioned but it is better to use business logic/ transaction logic outside of save() method. This would provide you better integrity and also abstraction.

Writing this logic inside save function is shorthand to do (pretty easy).

other way to do this

utils.py

def update_score(*args, **kwargs):
    with transaction.atomic():
        review = Review(*args, **kwargs)
        review.item.set_score()
        review.save()

If this wouldn't helpful for you than writing that transaction block inside save() method or simply pick your code into other method and wrap that with exception but handle that try-catch block with proper exception because it makes side effects / Buggy code. Rest of the things would be fine and work.

Just remember that do not handle exceptions inside the transaction atomic block.


推荐阅读