Эффективный путь к объемной вставке с get_or_create () в Django (SQL, Python, Django)

Существует ли более эффективный путь к тому, чтобы сделать это?

for item in item_list:
    e, new = Entry.objects.get_or_create(
        field1 = item.field1,
        field2 = item.field2,
    )
22
задан Cœur 7 September 2017 в 14:29
поделиться

4 ответа

С помощью get_or_create (или даже create) нельзя выполнять приличную массовую вставку (или даже создать), и нет API, чтобы легко это сделать.

Если ваша таблица достаточно проста, чтобы создавать строки с помощью необработанного SQL не слишком сложно, это не так уж сложно; что-то вроде:

INSERT INTO site_entry (field1, field2)
(
         SELECT i.field1, i.field2
         FROM (VALUES %s) AS i(field1, field2)
         LEFT JOIN site_entry as existing
                 ON (existing.field1 = i.field1 AND existing.field2 = i.field2)
         WHERE existing.id IS NULL
)

где% s - это строка типа ("field1, field2"), ("field3, field4"), ("field5, field6") , которую вам нужно будет создать и сбежать как следует.

10
ответ дан 29 November 2019 в 05:48
поделиться

Зависит от того, к чему вы стремитесь. Вы можете использовать функцию manage.py loaddata для загрузки данных в соответствующем формате (JSON, XML, YAML, ...).

См. Также это обсуждение .

4
ответ дан 29 November 2019 в 05:48
поделиться

Я бы сказал, что нет.

Но мне интересно, к какому типу относятся ваши item , если они имеют в качестве атрибутов field1 и field2 . Похоже, что существует другой класс, представляющий запись, но не производный от models.Model . Возможно, вы можете опустить этот класс и сразу создать экземпляры Entry вместо создания этих элементов.

0
ответ дан 29 November 2019 в 05:48
поделиться

Если вы не уверены, что вещи в вашем item_list уже существуют в вашей БД, и вам нужны объекты модели, то get_or_create определенно подойдет.

Если вы знаете, что этих объектов в вашей БД НЕТ, то лучше сделать так:

for item in item_list:
    new = Entry.objects.create(
        field1 = item.field1,
        field2 = item.field2,
    )

А если вам не нужны объекты, то просто игнорируйте возврат из вызова функции. Это не ускорит работу с БД, но поможет с управлением памятью, если это проблема.

Если вы не уверены, что данные уже есть в БД, но у любого поля есть флаг unique=True, то БД обеспечит уникальность, и вы можете просто поймать исключение и двигаться дальше. Это предотвратит лишнее попадание в БД, избежав попытки выбрать существующий объект.

from django.db import IntegrityError

for item in item_list:
    try:
        new = Entry.objects.create(
            field1 = item.field1,
            field2 = item.field2,
        )
    except IntegrityError:
        continue

Вы можете увеличить скорость в любом случае, если будете вручную управлять транзакциями. Django автоматически создает и фиксирует транзакцию для каждого сохранения, но предоставляет некоторые декораторы, которые значительно повышают эффективность, если вы знаете, что будете делать много сохранений в БД в определенной функции. Документация Django объясняет все это лучше, чем я здесь, но вы, вероятно, захотите обратить особое внимание на django.db.transaction.commit_on_success

0
ответ дан 29 November 2019 в 05:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: