Update 30.08.2023
There is a new queryset method select_for_update in most cases you probably want to use it instead.
First
As docs state
Atomicity is the defining property of database transactions. atomic allows us to create a block of code within which the atomicity on the database is guaranteed. If the block of code is successfully completed, the changes are committed to the database. If there is an exception, the changes are rolled back.
In your example you would need atomic if emit_event is doing something and you want this update to be done only if all emit_event function calls and queryset.update are successfull. But if states of emit_event does not affect your business logic of update, atomic here would be redundant because as you said yourself update has internal atomic.
Second
Querysets are lazy. Which means evaluation of queryset will be done when you are iterating over it. So you need to do something like this. Answering latest comment
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')
See there we make new queryset when iterating over it to get updated items