Массовое создание объектов модели в django


90

У меня есть много объектов для сохранения в базе данных, поэтому я хочу создать экземпляры модели с этим.

С помощью django я могу создать все экземпляры моделей с помощью MyModel(data), а затем я хочу сохранить их все.

В настоящее время у меня есть что-то вроде этого:

for item in items:
    object = MyModel(name=item.name)
    object.save()

Мне интересно, могу ли я сохранить список объектов напрямую, например:

objects = []
for item in items:
    objects.append(MyModel(name=item.name))
objects.save_all()

Как сохранить все объекты за одну транзакцию?


Кажется, дело идет к исправлению этого кода. Djangoproject.com/ticket/19527
DanH

1
Хотите узнать о list.save_all? Вы можете почти ответить себе, просто перефразируя это недоумение и используя два первых слова из вашего тематического вопроса.
Славомир Ленарт

Ответы:


95

на момент разработки django существует bulk_createметод диспетчера объектов, который принимает на вход массив объектов, созданных с помощью конструктора класса. проверить django docs


12
Документы Django для bulk_create: docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create
funkotron

1
Но помните, что у bulk_create есть некоторые ограничения, например, он не создает первичные ключи, если это AutoField, которое save () делает автоматически.
Hitesh Garg

@HiteshGarg, это все еще верно сейчас?
Raydel Miranda

1
@RaydelMiranda, да, это все еще правда. Это прямо в документации:If the model’s primary key is an AutoField it does not retrieve and set the primary key attribute, as save() does, unless the database backend supports it (currently only PostgreSQL).
interDist

1
Используя Django 3.0.x, я подтверждаю, что использование bulk_create()не вызывает никаких сигналов. Интересно, почему.
улучшение

43

Используйте bulk_create()метод. Теперь это стандарт в Django.

Пример:

Entry.objects.bulk_create([
    Entry(headline="Django 1.0 Released"),
    Entry(headline="Django 1.1 Announced"),
    Entry(headline="Breaking: Django is awesome")
])

1
Изменено в Django 1.10: добавлена ​​поддержка установки первичных ключей для объектов, созданных с помощью bulk_create () при использовании PostgreSQL.
elad silver

4

работал у меня, чтобы использовать ручную обработку транзакций для цикла (postgres 9.1):

from django.db import transaction
with transaction.commit_on_success():
    for item in items:
        MyModel.objects.create(name=item.name)

на самом деле это не то же самое, что и массовая вставка «родной» базы данных, но позволяет избежать / уменьшить затраты на транспорт / операции orms / анализ запросов sql


1
Это немного изменилось. Теперь транзакции commit_on_successбольше нет. Вы должны использовать transaction.atomic()См: stackoverflow.com/questions/21861207/...
t_io

4

Вот как массово создавать объекты из файла с разделителями столбцов, оставляя в стороне все процедуры отмены кавычек и отмены экранирования:

SomeModel(Model):
    @classmethod
    def from_file(model, file_obj, headers, delimiter):
        model.objects.bulk_create([
            model(**dict(zip(headers, line.split(delimiter))))
            for line in file_obj],
            batch_size=None)

3

для однострочной реализации вы можете использовать лямбда-выражение в карте

map(lambda x:MyModel.objects.get_or_create(name=x), items)

Здесь лямбда сопоставляет каждый элемент в списке элементов с x и при необходимости создает запись в базе данных.

Лямбда-документация


Вы, вероятно, захотите упомянуть, что над этим lambdaнадо mapбороться items:map(lambda name: MyModel.objects.get_or_create(name = name), items)
Манодж Говиндан

Ja, это еще один способ сказать (:
FallenAngel

2

Использование create вызовет один запрос для каждого нового элемента. Если вы хотите уменьшить количество запросов INSERT, вам нужно будет использовать что-то еще.

У меня был некоторый успех, используя фрагмент Bulk Insert, хотя он довольно старый. Возможно, потребуются некоторые изменения, чтобы он снова заработал.

http://djangosnippets.org/snippets/446/


2

Посмотрите это сообщение в блоге о модуле Bulkops .

В моем приложении django 1.3 я испытал значительное ускорение.


-19

Самый простой способ - использовать createметод Manager, который создает и сохраняет объект за один шаг.

for item in items:
    MyModel.objects.create(name=item.name)

+1. Если nameуникальны и возможны повторяющиеся входные данные, было бы неплохо использовать get_or_create.
Манодж Говиндан

16
Как это отвечает на вопрос? Model.objects.create эквивалентен object = MoModel (..) object.save (). И это не делает это за одну транзакцию ...
automagic
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.