Hello,
I’m sure there is a way, but how? For example:
class MyModel():
name = models.CharField()
rank = models.IntegerField()
And in a view:
MyModel.objects.create(
name='joe',
# DB-side, take the max existing "rank" across all entries and add one to it
rank=Max(F('rank'))+1
)
Obviously the syntax is wrong but hopefully the idea is conveyed.
thanks!
You can do something like this if want to
max_rank = MyModel.objects.aggregate(Max('rank')) # {'rank__max': 5}
max_rank = max_rank["rank__max"] + 1
MyModel.objects.create(
name='joe',
# DB-side, take the max existing "rank" across all entries and add one to it
rank=max_rank
)
ok thanks – but does that guarantee that when two requests are executed close enough in time together, they would not result both in rank=5
?
This seems to be like it works like this, but maybe I am mistaken:
- from python, make a database request asking for Max(rank)
- python-side, take that number and add 1 to it
- create the object
What I would like is:
- python side, create an object with the following directives:
{
'name': 'joe',
'rank': database-side (and not python-side) Max(rank)
}
where python would not be involved at all in determining the value of rank
.
You are correct. Trying to do this at all - even on the database side creates a race condition.
If you’re going to do this, you need to lock the table to perform the operation.
This topic has been discussed here a couple times before, I think you can find the discussions searching for “table lock”. In fact, one of the threads was a discussion between us about 20 months ago - F() expression on update // using Max() aggregate -- race condition