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)