Massenerstellung von Modellobjekten in Django

86

Ich muss viele Objekte in der Datenbank speichern und möchte damit Modellinstanzen erstellen.

Mit django kann ich alle Modellinstanzen erstellen, mit MyModel(data)und dann möchte ich sie alle speichern.

Derzeit habe ich so etwas:

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

Ich frage mich, ob ich eine Liste von Objekten direkt speichern kann, z.

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

Wie speichere ich alle Objekte in einer Transaktion?

Alexis Métaireau
quelle
Es scheint, dass der Ball bei der Implementierung eines Fixes
rollt.
1
Fragen Sie sich nach list.save_all? Sie könnten sich fast selbst beantworten, indem Sie diese Frage umschreiben und zwei erste Wörter aus Ihrer Themenfrage verwenden.
Sławomir Lenart

Antworten:

92

Ab der Django-Entwicklung gibt es bulk_createeine Objektmanager-Methode, die als Eingabe ein Array von Objekten verwendet, die mit dem Klassenkonstruktor erstellt wurden. Schauen Sie sich die Django-Dokumente an

ecbtln
quelle
12
Djangos Dokumente für bulk_create: docs.djangoproject.com/de/dev/ref/models/querysets/#bulk-create
funkotron
1
Denken Sie jedoch daran, dass Bulk_Create einige Einschränkungen aufweist, da keine Primärschlüssel erstellt werden, wenn es sich um ein AutoField handelt, das save () automatisch ausführt.
Hitesh Garg
@HiteshGarg, stimmt das heute noch?
Raydel Miranda
1
@ RaydelMiranda, ja es ist immer noch wahr. Es ist genau dort in der Dokumentation: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
Die Verwendung von Django 3.0.x und ich bestätigen, dass die Verwendung bulk_create()keine Signale auslöst. Ich wundere mich warum.
Enchance
39

Verwenden Sie die bulk_create()Methode. Es ist jetzt Standard in Django.

Beispiel:

Entry.objects.bulk_create([
    Entry(headline="Django 1.0 Released"),
    Entry(headline="Django 1.1 Announced"),
    Entry(headline="Breaking: Django is awesome")
])
Danil
quelle
1
In Django 1.10 geändert: Unterstützung für das Festlegen von Primärschlüsseln für Objekte, die mit mass_create () bei Verwendung von PostgreSQL erstellt wurden, wurde hinzugefügt.
Elad Silber
4

arbeitete für mich, um die manuelle Transaktionsbehandlung für die Schleife zu verwenden (postgres 9.1):

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

Tatsächlich ist es nicht dasselbe wie das Masseneinfügen einer 'nativen' Datenbank, aber es ermöglicht Ihnen, Transport- / Orms-Operationen / SQL-Abfrage-Analysekosten zu vermeiden / zu verringern

Eviltnan
quelle
Dies hat sich leicht geändert. Jetzt hat die Transaktion nicht commit_on_successmehr. Sie sollten transaction.atomic()See: stackoverflow.com/questions/21861207/…
t_io
4

So erstellen Sie Entitäten in großen Mengen aus spaltengetrennten Dateien, wobei alle nicht zitierenden und nicht entkommenden Routinen außer Acht gelassen werden:

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)
Ivan Klass
quelle
3

Für eine einzeilige Implementierung können Sie einen Lambda-Ausdruck in einer Karte verwenden

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

Hier ordnet Lambda jedes Element in der Elementliste x zu und erstellt bei Bedarf einen Datenbankeintrag.

Lambda-Dokumentation

Gefallener Engel
quelle
Sie wollen wahrscheinlich erwähnen , dass das lambdasein muss mapped über items:map(lambda name: MyModel.objects.get_or_create(name = name), items)
Manoj Govindan
Ja, das ist ein anderer Weg, den ich zu sagen versuche (:
FallenAngel
2

Die Verwendung von create führt zu einer Abfrage pro neuem Element. Wenn Sie die Anzahl der INSERT-Abfragen reduzieren möchten, müssen Sie etwas anderes verwenden.

Ich habe einige Erfolge mit dem Bulk Insert-Snippet erzielt, obwohl das Snippet ziemlich alt ist. Möglicherweise sind einige Änderungen erforderlich, damit es wieder funktioniert.

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

OmerGertel
quelle
2

Schauen Sie sich diesen Blog-Beitrag im Bulkops- Modul an.

In meiner Django 1.3-App habe ich eine erhebliche Beschleunigung erfahren.

MrJ
quelle
-19

Am einfachsten ist es, die createManager-Methode zu verwenden, mit der das Objekt in einem einzigen Schritt erstellt und gespeichert wird.

for item in items:
    MyModel.objects.create(name=item.name)
Daniel Roseman
quelle
+1. Wenn namees eindeutig ist und doppelte Eingaben möglich sind, ist es eine gute Idee, diese zu verwenden get_or_create.
Manoj Govindan
15
Wie beantwortet dies die Frage? Model.objects.create entspricht object = MoModel (..) object.save (). Und das macht es nicht in einer Transaktion ...
Automagic