webentwicklung-frage-antwort-db.com.de

So erhalten Sie Primärschlüssel von Objekten, die mit Django bulk_create erstellt wurden

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?

62
mikec

2016

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

51
Or Duan

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.

28
pyriku

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.

23
karthikr

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)
11
DanH

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.

0
peper0

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.

0
user3175220

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:

  1. 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

  2. Überschreiben/schreiben Sie Ihre eigene Bulk-Insert-Lösung.

0
Matt Seymour