I have 4 BaseReward objects, that have a default ordering of (rank, id) in Meta class. My aim is to update the objects such that I preserve their relative rankings, but give them unique ranks starting from 1,
Originally:
| id | rank |
|----|------|
| 1 | 3 |
| 2 | 2 |
| 3 | 2 |
| 4 | 1 |
after calling rerank_rewards_to_have_unique_ranks() should become
| id | rank |
|----|------|
| 1 | 4 |
| 2 | 2 |
| 3 | 3 |
| 4 | 1 |
I am trying to use F() expression with lookup .index() on list, but Django won't accept it as F() expression has only a fixed set of operators https://docs.djangoproject.com/en/1.8/topics/db/queries/#filters-can-reference-fields-on-the-model
Is there another way of achieving the same in an optimized way, without bringing the objects to database?
models.py
class BaseReward(models.Model):
class Meta:
ordering = ('rank', 'id')
# BaseReward.objects.all() gets the objects ordered by 'rank' as in the Meta class, and then by id if two objects have same rank
helper.py
def rerank_rewards_to_have_unique_ranks():
qs = BaseReward.objects.all() # this would give the rewards of that category ordered by [rank, id]
id_list_in_order_of_rank = list(qs.values_list('id', flat=True)) # get the ordered list of ids sequenced in order of ranks
# now I want to update the ranks of the objects, such that rank = the desired rank
BaseReward.objects.all().update(rank=id_list_in_order_of_rank.index(F('id'))+1)