Масове створення об’єктів моделі в django


90

У мене є багато об’єктів для збереження в базі даних, і тому я хочу створити з цим екземпляри Model.

За допомогою 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? Ви могли б майже відповісти собі, просто перефразовуючи це дивування, і використати 2 перші слова з вашого питання.
Славомір Ленарт

Відповіді:


95

станом на розвиток django, існує bulk_createяк метод менеджера об’єктів, який бере як вхід масив об’єктів, створених за допомогою конструктора класу. перегляньте документи django


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

1
Але пам’ятайте, що bulk_create має деякі обмеження, наприклад, він не створює первинні ключі, якщо це AutoField, який save () робить автоматично.
Hitesh Garg

@HiteshGarg, Це все ще правда сьогодні?
Рейдель Міранда

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)

насправді це не те саме, що і "рідна" базова вставка бази даних, але це дозволяє вам уникнути / зменшити кількість транспортних / ормових операцій / 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)
Манодж Говіндан

Джа, це ще один спосіб, я намагаюся сказати (:
FallenAngel

2

Використання create призведе до одного запиту на новий елемент. Якщо ви хочете зменшити кількість запитів 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.
Manoj Govindan

16
Як це відповідає на питання? Model.objects.create еквівалентно object = MoModel (..) object.save (). І це не робить цього за одну транзакцію ...
automagic
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.