Эффективное обновление одного и того же поля в нескольких объектах django

I have a model and I want to send increment a field value by 1 for multiple records. I searched for efficient update answers like Efficient way to update multiple fields of Django model object but they assume I have the value whereas I want to increment so the value might be different for different records.

Моя модель выглядит примерно так:

class Signal(models.Model):
    name = models.CharField(max_length=80)
    version = models.IntegerField()

По моему мнению, я хочу отправить список имен, а затем обновить все их версии на 1.

Мой текущий метод заключается в просмотре имен, создании объектов, обновлении версий и сохранении вручную следующим образом:

    signals = Signal.objects.filter(name__in=signal_names)
    for signal in signals:
        signal.pk=None
        signal.version = signal.version+1
        signal.save()

Это приводит к слишком большому количеству запросов и очень медленно, потому что я буду отправлять 100 имен одновременно.

Есть ли лучший способ сделать это?

ПРИМЕЧАНИЕ: Это может показаться похожим на вопросы о массовом обновлении, но в данном случае я хочу увеличить значение на 1, поэтому у меня нет значения для обновления. Это была моя проблема с существующими ответами.

Пример:

таблица сигналов

name | version
n1 | 1
n2 | 2

Я отправляю ["n1", "n2"] в своем сообщении, и результат должен быть таким

таблица сигналов

name | version
n1 | 1
n2 | 2
n1 | 2
n2 | 3

Вы можете составить список новых сигналов и создать их в базе данных массово с помощью .bulk_create(…) [Django-doc]:

# create new Signal objects

results = []
signals = Signal.objects.filter(name__in=signal_names)

for signal in signals:
    signal.pk = None
    signal.version += 1
    results.append(signal)

Signal.objects.bulk_create(results)

Однако это приведет к появлению дубликатов. Если вы хотите обновить существующие Signal, то работайте с .update(…) [Django-doc]:

# updating the existing the Signal objects

signals = Signal.objects.filter(name__in=signal_names).update(
    version=F('version') + 1
)

Если вы хотите получить только последнюю версию, вам следует изменить набор запросов signals с помощью подзапроса Exists [Django-doc]:

from django.db.models import Exists, OuterRef

Signal.objects.filter(
    ~Exists(Signal.objects.filter(
        name=OuterRef('name'), version__gt=OuterRef('version')
    )),
    name__in=signal_names,
)
Вернуться на верх