2016-12-01 3 views
1

Я пытаюсь обновить поле набора запросов атомарно. У меня есть что-то вроде этого:Обновление каждого экземпляра в наборе запросов с помощью count atomically

counter = 0 
for row in myQuerySet: 
    row.myField = counter 
    counter = counter + 1 
    row.save() 

Это работает, но я хочу сделать это атомарно, потому что у меня есть сотни регистров, и это пустая трата времени. Мне нужно что-то вроде этого:

counter = 0 
myQuerySet.update(myField=(counter+=1)) 

Но это не работает. Каков правильный синтакс для этого?

+1

Оператор update создает один SQL-запрос, и если вы используете значение, которое не является частью таблицы (т. Е. Оно не является полем), оно будет считаться константой, и в этом случае все строки будут обновляться одинаковыми стоимость. – AKS

+1

Объекты 'F()' могут помочь обновить поле на основе существующего значения поля, но я не могу придумать способ обновления поля на основе возрастающего внешнего значения. –

+0

@Sayse У меня много регистров с целым полем «step_number». Это поле может быть изменено вручную, и вы можете получить инкрементную последовательность с зазорами, например, если у вас есть 5 регистров, их step_numbers могут быть 1,2,3,8,9. Но я хочу перенумеровать это, чтобы получить последовательность 1,2,3,4,5. Такова цель счетчика. – MouTio

ответ

2

Это работает, но я хочу сделать это атомарно [...]

Часто, ответ заключается в использовании QuerySet.update method. Это работает, когда вы хотите сделать то же самое - или что-то, что не нужно менять динамически - ко всем экземплярам в наборе запросов.

Поскольку операция, которую вы хотите выполнить, требует динамического изменения для каждого экземпляра по очереди, вместо этого вы можете использовать select_for_update method.

from django.db import transaction 

dolors = LoremIpsum.objects.select_for_update().filter(dolor=True) 

with transaction.atomic(): 
    counter = 0 
    for lorem_ipsum in dolors: 
     lorem_ipsum.amet = counter 
     counter += 1 
     lorem_ipsum.save() 

documentation for select_for_update говорит, что это делает то, что вы хотите:

Все совпадающие записи будут заблокированы до конца блока транзакции, а это означает, что другие операции будут предотвращены от изменения или приобретения замков на них ,

Поскольку QuerySet вызывает элементы не должны быть «закрыты до конца блока транзакции», вам необходимо выполнить свои операции внутри блока транзакции с использованием transaction.atomic, как указано выше.

+1

Вот и все! Перед элементом select_for_update отсутствует часть «объектов», и я добавлю только что добавить «with transaction.atomic()» (из транзакции импорта django.db), потому что select_for_update не может использоваться вне транзакции. – MouTio