Эффективный способ для массовой вставки с помощью get_or_create () в Django (SQL, Python, Django)

17

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

for item in item_list:
    e, new = Entry.objects.get_or_create(
        field1 = item.field1,
        field2 = item.field2,
    )
    
задан kemar 12.02.2010 в 15:44
источник
  • В одном комментарии вы сказали, что вам нужны модели. Вы также сказали, что вы использовали executemany. Как вы получили модели при использовании executemany? –  Eddified 16.03.2010 в 17:22

5 ответов

8

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

    
ответ дан Glenn Maynard 12.02.2010 в 20:13
  • Как я это сделал, вы можете вставлять множество (сотни) строк в одном запросе, так как обычно вы хотите делать пакетные вставки. –  Glenn Maynard 16.02.2010 в 00:05
  • Да, но я не могу это сделать с MySQL. Кажется, я не могу найти правильный синтаксис SQL с предлагаемым запросом. –  kemar 16.02.2010 в 01:04
  • Как насчет получить? Как вы собираетесь получить модельный объект, запустив этот запрос? –  Software Enthusiastic 06.01.2011 в 08:50
  • Можно ли это сделать с помощью новой объемной вставки? docs.djangoproject.com/en/dev/releases/1.4/...? –  dzen 24.03.2012 в 01:26
  • Это может быть полезно, stackoverflow.com/questions/20747117/... –  radtek 09.01.2015 в 14:40
4

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

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

    
ответ дан Felix Kling 12.02.2010 в 15:48
  • , это некорректная ссылка сейчас –  wim 22.12.2015 в 17:33
1

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

ответ дан Paul McLanahan 12.02.2010 в 16:42
  • элементы в моем item_list могут уже существовать в моей БД, и да, мне нужны объекты модели. И ни одно из полей не имеет уникального = True constraint: '(Итак, я думаю, что get_or_create - это путь. Давайте попали в базу данных! –  kemar 12.02.2010 в 17:23
  • Это не отвечает на вопрос. Во-первых, он сказал, что хочет навалом вставить; «get_or_create - это путь» не помогает, поскольку get_or_create не выполняет массовые вставки. Вставка элементов по одному - это неправильная вещь для массового вставки. Наконец, вы не можете просто вызывать ошибки, а затем игнорировать их; в Postgresql вы получите ошибки с транзакцией, если вы не перевернете контрольные точки. –  Glenn Maynard 12.02.2010 в 19:56
1

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

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

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

    
ответ дан Gumbah 09.03.2013 в 12:44
0

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

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

ответ дан Johannes Charra 12.02.2010 в 15:58