Эффективный способ для массовой вставки с помощью 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,
    )

Ответ 1

Вы не можете делать приличные массовые вставки с помощью get_or_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"), которую вы должны будете создать и убежать должным образом самостоятельно.

Ответ 2

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

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

Ответ 3

Если вы не уверены, что вещи в вашем item_list уже существуют в вашей базе данных, и вам нужны объекты модели, тогда get_or_create - это определенно путь.

Если вы знаете, что элементы НЕ в вашей БД, вы бы гораздо лучше сделали:

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

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

Если вы не уверены, что данные уже находятся в БД, но в этом поле есть флаг 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

Ответ 4

Начиная с 1.4 вы можете делать bulk_create

Смотрите документы

* Обратите внимание на предостережения, хотя (самое главное, что метод save() не будет вызываться, и поэтому сигналы pre_save и post_save не будут отправлены.) *

Ответ 5

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

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