Masowo twórz obiekty modelu w django


90

Mam wiele obiektów do zapisania w bazie danych, dlatego chcę z nimi tworzyć instancje modelu.

Dzięki django mogę tworzyć wszystkie instancje modeli MyModel(data), a następnie chcę je wszystkie zapisać.

Obecnie mam coś takiego:

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

Zastanawiam się czy mogę bezpośrednio zapisać listę obiektów np:

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

Jak zapisać wszystkie obiekty w jednej transakcji?


Wygląda na to, że piłka toczy się po wprowadzeniu poprawki dla tego kodu. Djangoproject.com/ticket/19527
DanH,

1
zastanawiasz się nad list.save_all? Możesz prawie sobie odpowiedzieć, parafrazując to zastanowienie i używając 2 pierwszych słów z pytania tematycznego.
Sławomir Lenart

Odpowiedzi:


95

od czasu rozwoju django istnieje bulk_createmetoda menedżera obiektów, która przyjmuje jako dane wejściowe tablicę obiektów utworzonych przy użyciu konstruktora klasy. sprawdź dokumentację django



1
Pamiętaj jednak, że bulk_create ma pewne ograniczenia, takie jak nie tworzy kluczy podstawowych, jeśli jest to funkcja AutoField, która funkcja save () robi automatycznie.
Hitesh Garg

@HiteshGarg, czy to nadal prawda?
Raydel Miranda

1
@RaydelMiranda, tak, to nadal prawda. Znajduje się w dokumentacji: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
Używając Django 3.0.x i potwierdzam, że używanie bulk_create()nie wyzwala żadnych sygnałów. Zastanawiam się dlaczego.
enchance

42

Użyj bulk_create()metody. Jest teraz standardem w Django.

Przykład:

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

1
Zmieniono w Django 1.10: Dodano obsługę ustawiania kluczy podstawowych w obiektach utworzonych przy użyciu bulk_create () podczas korzystania z PostgreSQL.
elad silver

4

pracował dla mnie, aby użyć ręcznej obsługi transakcji dla pętli (postgres 9.1):

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

w rzeczywistości to nie to samo, co „natywne” wstawianie zbiorcze do bazy danych, ale pozwala uniknąć / zmniejszyć transport / operacje orms / kwerendę sql analizować koszty


1
To nieco się zmieniło. Teraz transakcji już nie ma commit_on_success. Powinieneś użyć transaction.atomic()Zobacz: stackoverflow.com/questions/21861207/ ...
t_io

4

Oto jak zbiorczo tworzyć encje z pliku rozdzielanego kolumnami, pomijając wszystkie procedury bez cytowania i zmiany znaczenia:

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

w przypadku implementacji jednowierszowej w mapie można użyć wyrażenia lambda

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

Tutaj lambda dopasowuje każdą pozycję na liście pozycji do x i tworzy rekord bazy danych, jeśli to konieczne.

Dokumentacja Lambda


Prawdopodobnie chcesz wspomnieć, że lambdatrzeba go mapprzerzucić items:map(lambda name: MyModel.objects.get_or_create(name = name), items)
Manoj Govindan

Ja, to inny sposób próbuję powiedzieć (:
FallenAngel

2

Użycie create spowoduje jedno zapytanie na nowy element. Jeśli chcesz zmniejszyć liczbę zapytań INSERT, musisz użyć czegoś innego.

Udało mi się użyć fragmentu wstawiania zbiorczego, mimo że jest on dość stary. Być może konieczne są pewne zmiany, aby ponownie działał.

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


2

Zapoznaj się z tym postem na blogu dotyczącym modułu zbiorczego .

W mojej aplikacji django 1.3 doświadczyłem znacznego przyspieszenia.


-19

Najłatwiej jest skorzystać z createmetody Manager, która tworzy i zapisuje obiekt w jednym kroku.

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

+1. Jeśli namejest unikalny i możliwe są zduplikowane dane wejściowe, dobrym pomysłem byłoby użycie get_or_create.
Manoj Govindan

16
Jak to odpowiada na pytanie? Model.objects.create jest odpowiednikiem object = MoModel (..) object.save (). I to nie robi tego w jednej transakcji ...
automagic
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.