Эффективное обновление одного и того же поля в нескольких объектах 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,
)