Max() on objects.create()

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. :slight_smile:
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