Wie füge ich in Django mehrere Objekte gleichzeitig zur ManyToMany-Beziehung hinzu?

183

Basierend auf dem Django-Dokument sollte es mir möglich sein, mehrere Objekte gleichzeitig zu übergeben, um sie zu einer Vielzahl von Beziehungen hinzuzufügen, aber ich erhalte eine

* TypeError: nicht zerlegbarer Typ: 'Liste'

wenn ich versuche, ein Django-Abfrageset zu übergeben, das in einer Liste enthalten ist. Das Übergeben eines Querysets oder eines ValuesListQueryset scheint ebenfalls fehlzuschlagen. Gibt es einen besseren Weg als eine for-Schleife?

philgo20
quelle

Antworten:

317

Verwendung: object.m2mfield.add(*items)wie in der Dokumentation beschrieben :

add() akzeptiert eine beliebige Anzahl von Argumenten, keine Liste von ihnen.

add(obj1, obj2, obj3, ...)

Verwenden Sie, um diese Liste in Argumente zu erweitern *

add(*[obj1, obj2, obj3])

Nachtrag:

Django ruft nicht obj.save()für jeden Gegenstand auf, sondern verwendet ihn bulk_create()stattdessen.

Yuji 'Tomita' Tomita
quelle
Wenn Sie sich den Manager ansehen, führt er nur eine for-Schleife über die Objekte durch und ruft sie auf.
Sam Dolan
3
Ein kurzes Experiment aus der Shell zeigt, dass @sdolan tatsächlich (derzeit) falsch ist. Wenn ich mir das generierte SQL anschaue, sehe ich nur eine einzige Einfügeanweisung: INSERT INTO app_one_twos (one_id, two_id) VALUES (1, 1), (1, 2), (1, 3), (1, 4); Dies ist in Django 1.4.
Klaas van Schelven
@KlaasvanSchelven: Ich kann mich nicht erinnern, dies über die generierte SQL getestet zu haben, aber aufgrund meines Kommentars bin ich mir ziemlich sicher, dass ich nur einen Blick auf den Quellcode geworfen habe. Denken Sie daran, dass dies vor über 2 Jahren war, also würde ich hoffen, dass die Dinge ein bisschen optimiert wurden.
Sam Dolan
1
@sdolan Nein, sie haben es nicht verbessert. Ich habe es gerade getestet.
Saransh Mohapatra
1
Gibt es eine Möglichkeit, dies nach Wert (z. B. ID) zu tun? Manchmal haben Sie keine Liste von Objekten, sondern eine Liste von Objektwerten (dh IDs)? Anstatt alle Objekte zu durchlaufen und in eine andere Liste zu
packen
47

Hinzufügen, wenn Sie sie aus einem Abfragesatz hinzufügen möchten

Beispiel

# Returns a queryset
permissions = Permission.objects.all()

# Add the results to the many to many field (notice the *)

group = MyGroup.objects.get(name='test')

group.permissions.add(*permissions)

Von: Fügen Sie Abfragesatzergebnisse in ManytoManyfield ein

Dr. Manhattan
quelle
3
Dies führt zwei Abfragen anstelle von einer aus :(
DylanYoung
1
Beachten Sie, dass Sie es nicht in eine Liste umwandeln müssen. Fügen Sie einfach (* Berechtigungen) direkt hinzu.
BjörnW
34

Django 1.9 bietet zusätzliche Möglichkeiten zum Hinzufügen zu einer Viele-zu-Viele-Beziehung.

Dokumentation: https://docs.djangoproject.com/de/dev/ref/models/relations/#django.db.models.fields.related.RelatedManager.set

set ist eine neue Schönheit:

>>> new_list = [obj1, obj2, obj3]
>>> e.related_set.set(new_list)
Aero
quelle
2
setwar immer da, denke ich. Es ist nur so, dass es früher e.related_set = new_listbei älteren Djangos gleichbedeutend mit Aufgaben war e.related_set.set(new_list). Sie haben gerade erkannt, dass "explizit besser ist als implizit".
DylanYoung
1
Achtung: Um es kurz zu machen, löscht set alle vorhandenen zugeordneten Modelle. Wenn Sie also eine Liste neuer Objekte hinzufügen und die vorhandene intakt halten möchten, verwenden Sie add (* newlist)
Tasawar Hussain