I have a model similar to this example
class Foo(models.Model):
a = models.ForeignKey(...)
number = models.IntegerField()
@transaction.atomic
def save(self, commit=True):
if self.pk is None:
current_max = (
Foo.objects
.filter(a=self.a)
.order_by('-number')
.first()
)
current_max = 0 if current_max is None else current_max.number
self.number = current_max + 1
return super().save(commit)
The idea is that for each a
, there will be a series of Foo
s numbered from 1 and then onwards.
The issue is that, even though we have @transaction.atomic
, there is a race condition, because the transaction isolation level that Django expects will allow the transactions to run simultaneously, i.e.
A -> Get max -> 42
B -> Get max -> 42
A -> Set max + 1
A -> save
B -> Set max + 1
B -> save
Both will be 43
So how would I go about solving that? Is there a way to atomically setting the counter so I don't get the race condition between retrieving the current max and inserting the new value?
This question is similar to this one, but different enough that that question did not provide an answer to my specific example