Django обновляет строки на основе порядка в наборе запросов

У меня есть простая модель django

class Item(Model):
  name = CharField()
  rank = PositiveIntegerField()
  created_at = DateField(auto_now_add=True)

Я хочу обновить ранг объектов на основе их порядка при сортировке по полю (имя или created_at). например, при упорядочивании по имени

[("Pen", 0, "2021-05-04"), ("Ball", 0, "2021-05-04")] => [("Pen", 1, "2021-05-04"), (Ball, 0, "2021-05-04")] 

Я уже знаю, что могу сделать это с помощью bulk_update, но это означает, что я должен получить объекты в памяти

items = Items.objects.order_by("name")
for i, item in enumerate(items):
  item.rank = i
Item.objects.bulk_update(items, ["rank"])

Мне интересно, есть ли способ сделать это с помощью 1 запроса непосредственно в базе данных, без необходимости получения данных

CREATE TABLE items (
    id serial PRIMARY KEY,
    name VARCHAR ( 50 ) UNIQUE NOT NULL,
    rank smallint
);

insert into items(id, name, rank) values (1, 'A', 0);
insert into items(id, name, rank) values (2, 'B', 0);
insert into items(id, name, rank) values (3, 'C', 0);
select * from items;
id name rank
1 A 0
2 B 0
3 C 0
UPDATE items
SET rank=calculated.calc_rank
FROM
  (SELECT id AS calc_id,
          (ROW_NUMBER() OVER (
                              ORDER BY name ASC)) AS calc_rank
   FROM items) AS calculated
WHERE items.id = calculated.calc_id;
select * from items;
id name rank
1 A 1
2 B 2
3 C 3

И выполняйте необработанный SQL для Django:

sql = '''
UPDATE items
SET rank=calculated.calc_rank
FROM
  (SELECT id AS calc_id,
          (ROW_NUMBER() OVER (
                              ORDER BY name ASC)) AS calc_rank
   FROM items) AS calculated
WHERE items.id = calculated.calc_id
'''

with connection.cursor() as cursor:
  cursor.execute(sql)
Вернуться на верх