似乎Django
的queryset.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')
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当它迭代得到更新的项