Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update every instance in a queryset with a count atomically

I am trying to update a field of a queryset atomically. I have something like this:

counter = 0
for row in myQuerySet:
  row.myField = counter
  counter = counter + 1
  row.save()

That works, but I want to do this atomically, because I have hundreds of registers and it is a waste of time. I need something like this:

counter = 0
myQuerySet.update(myField=(counter+=1))

But that does not work. What is the correct sintax for this?

like image 960
MouTio Avatar asked Dec 14 '25 18:12

MouTio


1 Answers

That works, but I want to do this atomically […]

Often, the answer is to use the QuerySet.update method. That works when you want to do the same thing – or something that doesn't need to change dynamically – to all the instances in a queryset.

Since the operation you want to perform appears to need a dynamic change to each instance in turn, you can instead use the select_for_update method.

from django.db import transaction

dolors = LoremIpsum.objects.select_for_update().filter(dolor=True)

with transaction.atomic():
    counter = 0
    for lorem_ipsum in dolors:
        lorem_ipsum.amet = counter
        counter += 1
        lorem_ipsum.save()

The documentation for select_for_update says this does what you want:

All matched entries will be locked until the end of the transaction block, meaning that other transactions will be prevented from changing or acquiring locks on them.

Because the queryset causes the items to be “locked until the end of the transaction block”, you need to perform your operations inside a transaction block using transaction.atomic as above.

like image 81
bignose Avatar answered Dec 18 '25 00:12

bignose



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!