[Fixed]-Django: Transaction and select_for_update()

9👍

Doing select_for_update() on an EventRegistration queryset isn’t the way to go. That locks the specified rows, but presumably the conflict you’re trying to prevent involves creating new EventRegistrations. Your lock won’t prevent that.

Instead you can acquire a lock on the Event. Something like:

class Event(models.Model):
    ...
    @transaction.atomic
    def reserve_tickets(self, number_tickets):
        list(Event.objects.filter(id=self.id).select_for_update())  # force evaluation
        if self.get_number_of_registered_tickets() + number_tickets <= self.capacity:
            # create EventRegistration
        else:
            # handle error

Note that this uses the transaction.atomic decorator to make sure you are running inside a transaction.

4👍

Note that in multiple database environment you must have atomic and select_for_update on the same db, otherwise it wont work

with transaction.atomic(using='dbwrite'):
     Model.objects.using('dbwrite').select_for_update()....
👤James

Leave a comment