django queryset.update(**kwargs)上的原子事务



似乎Djangoqueryset.update方法在transaction.atomic上下文管理器下执行。在update期间,我什么时候需要在我的代码中显式地这样做?或者这样做的好处是什么,不这样做的问题是什么?

try:
    queryset = Model.objects.filter(a=1)
    if queryset.count():
        with transaction.atomic():
            queryset.update(a=2) # queryset will [] after this.
            for item in queryset: 
                item.emit_event('Updated')
except:
    logger.info('Exception')

我的问题是,我真的需要有transaction.atomic():在这里吗?

其次,在.update之后,我的查询集变为空,因为它是一个过滤的查询集。如何在我的情况下保留值,因为我想在单个对象上发出一个事件。

First

As docs state

原子性是数据库事务的定义属性。Atomic允许我们创建一个代码块,在这个代码块中可以保证数据库的原子性。如果代码块成功完成,则将更改提交到数据库。如果有异常,则回滚更改。

在您的示例中,如果emit_event正在做某事,则需要atomic,并且您希望仅在所有emit_event函数调用和queryset.update都成功时才进行此更新。但是,如果emit_event的状态不影响您的业务逻辑的更新,atomic这里将是多余的,因为正如您自己所说,update有内部的atomic

第二

查询集是惰性的。也就是说,当你迭代查询集的时候,就会对它进行求值。所以你需要这样做。回复最新评论

try:
    queryset = Model.objects.filter(a=1)
    item_ids = list(queryset.values_list('id', flat=True)) # store ids for later
    if item_ids: # optimzing here instead of queryset.count() so there won't be hit to DB
        with transaction.atomic():
            queryset.update(a=2) # queryset will [] after this.
            for item in Model.objects.filter(id__in=item_ids):  # <- new queryset which gets only updated objects
                item.emit_event('Updated')
except:
    logger.info('Exception')

看到了吗,在这里我们创建了一个新的queryset当它迭代得到更新的项

最新更新