Эффективный способ массовой вставки с помощью get_or_create () в Django (SQL, Python, Django) - PullRequest
20 голосов
/ 12 февраля 2010

Есть ли более эффективный способ сделать это?

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

Ответы [ 5 ]

10 голосов
/ 12 февраля 2010

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

4 голосов
/ 12 февраля 2010

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

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

2 голосов
/ 12 февраля 2010

Если вы не уверены, что вещи из вашего 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

1 голос
/ 09 марта 2013

Начиная с версии 1.4, вы можете сделать Навальный_Создать

См. документы

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

0 голосов
/ 12 февраля 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...