Gibt es eine Möglichkeit, die Primärschlüssel der Elemente abzurufen, die Sie mit der Funktion bulk_create in Django 1.4+ erstellt haben?
Seit Django 1.10 - wird es jetzt (nur auf Postgres) unterstützt. Hier ist ein Link zum Dokument) .
>>> list_of_objects = Entry.objects.bulk_create([
... Entry(headline="Django 2.0 Released"),
... Entry(headline="Django 2.1 Announced"),
... Entry(headline="Breaking: Django is awesome")
... ])
>>> list_of_objects[0].id
1
Aus dem Änderungsprotokoll:
Geändert in Django 1.10: Unterstützung für das Setzen von Primärschlüsseln für Objekte, die mit bulk_create () bei Verwendung von PostgreSQL erstellt wurden, wurde hinzugefügt
Laut Dokumentation können Sie das nicht tun: https://docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create
bulk-Create ist genau das Richtige: Erstellen Sie viele Objekte auf effiziente Weise und sparen Sie dabei viele Abfragen. Dies bedeutet jedoch, dass die Antwort unvollständig ist. Wenn Sie tun:
>>> categories = Category.objects.bulk_create([
Category(titel="Python", user=user),
Category(titel="Django", user=user),
Category(titel="HTML5", user=user),
])
>>> [x.pk for x in categories]
[None, None, None]
Das bedeutet nicht, dass Ihre Kategorien kein pk haben, nur, dass die Abfrage sie nicht abgerufen hat (wenn der Schlüssel ein AutoField
ist). Wenn Sie die pks aus irgendeinem Grund möchten, müssen Sie die Objekte auf klassische Weise speichern.
Zwei Ansätze, die ich mir vorstellen kann:
a) Das könntest du tun
category_ids = Category.objects.values_list('id', flat=True)
categories = Category.objects.bulk_create([
Category(title="title1", user=user, created_at=now),
Category(title="title2", user=user, created_at=now),
Category(title="title3", user=user, created_at=now),
])
new_categories_ids = Category.objects.exclude(id__in=category_ids).values_list('id', flat=True)
Dies kann ein wenig teuer sein, wenn der Abfragesatz extrem groß ist.
b) Wenn das Modell ein created_at
Feld,
now = datetime.datetime.now()
categories = Category.objects.bulk_create([
Category(title="title1", user=user, created_at=now),
Category(title="title2", user=user, created_at=now),
Category(title="title3", user=user, created_at=now),
])
new_cats = Category.objects.filter(created_at >= now).values_list('id', flat=True)
Dies hat die Einschränkung, dass ein Feld gespeichert wird, als das Objekt erstellt wurde.
Eigentlich hat mein Kollege die folgende Lösung vorgeschlagen, die jetzt alles so offensichtlich scheint. Fügen Sie eine neue Spalte mit dem Namen bulk_ref
Hinzu, die Sie mit einem eindeutigen Wert füllen, und fügen Sie ihn für jede Zeile ein. Fragen Sie anschließend einfach die Tabelle mit dem zuvor eingestellten bulk_ref
Ab und voila, Ihre eingefügten Datensätze werden abgerufen. z.B.:
cars = [Car(
model="Ford",
color="Blue",
price="5000",
bulk_ref=5,
),Car(
model="Honda",
color="Silver",
price="6000",
bulk_ref=5,
)]
Car.objects.bulk_create(cars)
qs = Car.objects.filter(bulk_ref=5)
Die wahrscheinlich einfachste Problemumgehung besteht darin, Primärschlüssel manuell zuzuweisen. Dies hängt vom Einzelfall ab, aber manchmal reicht es aus, mit max (id) +1 aus der Tabelle zu beginnen und jedem Objekt inkrementelle Nummern zuzuweisen. Wenn jedoch mehrere Clients gleichzeitig Datensätze einfügen, ist möglicherweise eine Sperre erforderlich.
Dies funktioniert in Standard-Django nicht, aber es gibt einen Patch im Django Bug-Tracker , der bulk_create veranlasst, die Primärschlüssel für erstellte Objekte festzulegen.
Die Django-Dokumentation besagt derzeit unter den Einschränkungen:
Wenn der Primärschlüssel des Modells ein AutoField ist, wird das Primärschlüsselattribut nicht wie bei
save()
abgerufen und festgelegt.
Aber es gibt gute Neuigkeiten. Es gab ein paar Tickets über bulk_create
aus dem Speicher. Das oben aufgeführtes Ticket hat mit größter Wahrscheinlichkeit eine Lösung, die bald implementiert wird. Es gibt jedoch offensichtlich keine Garantie dafür, dass die Lösung rechtzeitig eintrifft oder jemals eintrifft.
Es gibt also zwei mögliche Lösungen:
Warten Sie ab, ob dieser Patch in Produktion geht. Sie können dabei helfen, indem Sie die angegebene Lösung testen und der Django= Community Ihre Gedanken/Probleme mitteilen. https://code.djangoproject.com/attachment/ticket/19527 /bulk_create_and_create_schema_Django_v1.5.1.patch
Überschreiben/schreiben Sie Ihre eigene Bulk-Insert-Lösung.