Django: обновить несколько строк значением из отношения - PullRequest
0 голосов
/ 21 февраля 2020

У нас есть тысячи строк в нашей БД, для которых требуется миграция базы данных. У нас так много строк, которые охватывают 8 лет, и для нас не реально запустить save() для каждого отдельного экземпляра, как в следующем примере:

update_list = OrderProduct.objects.filter(
    product__isnull=False,
    title="unnamed")

for op in update_list:
    op.title = op.product.title
    op.save()  # We would prefer a update() query rather than individual saves

Итак, мы пытаемся сделать это с запросом БД. Я знаю, что F() не поддерживает объединения при использовании его внутри update(), поэтому я пытался быть умным со следующим:

OrderProduct.objects\
    .filter(title="unnamed", product__isnull=False)\
    .annotate(copy_title=F('product__title'))\
    .update(title=F('copy_title'))

К сожалению, это не работает, поэтому мне интересно, есть ли простой способ добиться этого с помощью django update (), вместо циклического перебора каждой строки.

1 Ответ

1 голос
/ 21 февраля 2020

импорт:

from django.db import transaction
from bulk_update.helper import bulk_update

Вам необходимо поместить строки в список, являющийся параметром функций create_objects & update_objects

Вы можете попробовать bulk_create:

    def create_objects(create_objects: list, chunk_size=2000):
    if len(create_objects):
        with transaction.atomic():
            model_cls: Model = create_objects[0].__class__
            for chunk_list in ModelHelpers.chunk_iterate(create_objects, chunk_size):
                model_cls.objects.bulk_create(chunk_list)

    return create_objects

и bulk_update:

    @staticmethod
    def update_objects(update_objects: list, update_fields=None, chunk_size=2000):
    if update_objects:
        with transaction.atomic():
            for chunk_list in ModelHelpers.chunk_iterate(update_objects, chunk_size):
                bulk_update(chunk_list, update_fields=update_fields)

Вам нужна функция chunk_iterate для них:

    @staticmethod
    def chunk_iterate(lst, n):
    """Yield successive n-sized chunks from lst."""
    for i in range(0, len(lst), n):
        yield lst[i:i + n]

Надеюсь, это поможет,

...