Массовое обновление поля модели на основе условия

У меня есть модель из 5 столбцов с примерно 10 000+ строк данных. Теперь я хочу обновить один столбец из всех строк на основе значений других столбцов.

Современная функция django для массового обновления - bulk_update(). Вот пример:

myModel = MyModel.objects.all()

for l in myModel:
    if c1=='ChkVal1' and c2 < c3:    
        c4='Value 1'
    elif c1=='ChkVal2' and c2 b> c3:
        c4='Value 2'
    else
        c4='Value 3'

MyModel.objects.bulk_update(myModel, update_fields = ['c4'])

Помните:

  • Вы не можете обновить первичный ключ модели.
  • Не вызывается метод save() каждой модели, и сигналы pre_save и post_save не посылаются.
  • При обновлении большого количества столбцов в большом количестве строк генерируемый SQL может быть очень большим. Избежать этого можно, указав подходящий размер партии (batch_size).
  • Обновление полей, определенных в предках, наследующих многотабличное наследование, повлечет за собой дополнительный запрос на каждого предка.
  • Когда отдельная партия содержит дубликаты, только первый экземпляр в этой партии приведет к обновлению.

Параметр batch_size управляет тем, сколько объектов сохраняется в одном запросе. По умолчанию все объекты обновляются в одном пакете, за исключением SQLite и Oracle, которые имеют ограничения на количество переменных, используемых в запросе

.

На мой взгляд, для вашего сценария "Я хочу обновить один столбец из всех строк на основе значений других столбцов" , лучшим вариантом будет использование Условного обновления

Предположим такую модель:

class Person(models.Model):
    f1 = models.IntegerField()
    f2 = models.IntegerField()
    f3 = models.IntegerField()
    f4 = models.IntegerField()

Обновить его можно следующим образом:

rom django.db.models import F, When, Case

new_value = Case(
    When(f1__gte=F('f2'), then=F('f1')),
    default=F('f2') 
)

Person.objects.update(f3=new_value)

Поднимите простой sql-запрос обновления:

>>> import logging
>>> l = logging.getLogger('django.db.backends')
>>> l.setLevel(logging.DEBUG)
>>> l.addHandler(logging.StreamHandler())
>>> Person.objects.update(f3=c)
(0.000) UPDATE "tt_person" SET "f3" = CASE WHEN ("tt_person"."f1" >= "tt_person"."f2") THEN "tt_person"."f1" ELSE "tt_person"."f2" END; args=()
0
Вернуться на верх