Come aggiungere più oggetti alla relazione ManyToMany contemporaneamente in Django?


185

Basato sul documento Django, dovrei essere in grado di passare più oggetti contemporaneamente per essere aggiunto a una relazione di molte persone, ma ottengo un

* TypeError: tipo non lavabile: 'list'

quando provo a passare un queryset django inserito in un elenco. Anche il passaggio di un Queryset o di un ValuesListQueryset sembra fallire. C'è un modo migliore di usare un ciclo for?

Risposte:


320

Usa: object.m2mfield.add(*items)come descritto nella documentazione :

add() accetta un numero arbitrario di argomenti, non un elenco di essi.

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

Per espandere tale elenco in argomenti, utilizzare *

add(*[obj1, obj2, obj3])

Addendum:

Django non chiama obj.save()per ogni oggetto ma usa bulk_create()invece.


Se guardi il gestore, esegue semplicemente un ciclo for sugli oggetti e le chiamate li salvano.
Sam Dolan,

3
Un breve esperimento dalla shell mostra che @sdolan è in realtà (attualmente) errato. Vale a dire quando guardo l'SQL generato vedo solo una singola istruzione insert: INSERT INTO app_one_twos (one_id, two_id) VALUES (1, 1), (1, 2), (1, 3), (1, 4); Questo è in Django 1.4.
Klaas van Schelven,

@KlaasvanSchelven: non ricordo di averlo provato attraverso il sql generato, ma in base al mio commento sono abbastanza sicuro di aver appena dato un'occhiata al codice sorgente. Tieni presente che è successo oltre 2 anni fa, quindi spero che le cose siano state un po 'ottimizzate.
Sam Dolan,

1
@sdolan No, non l'hanno migliorato. Lo stavo solo testando.
Saransh Mohapatra,

1
Un modo per farlo in base al valore (es. Id)? A volte non hai un elenco di oggetti ma un elenco di valori di oggetti (cioè ID)? Piuttosto che scorrere e afferrare tutti gli oggetti in un altro elenco ...
DannyMoshe,

48

Per aggiungere, se si desidera aggiungerli da un set di query

Esempio

# 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)

Da: inserire i risultati del queryset in ManytoManyfield


3
Questo esegue due query anziché una :(
DylanYoung,

2
Nota che non è necessario trasformarlo in un elenco. Basta aggiungere (* autorizzazioni) direttamente.
BjornW,

34

Django 1.9 aggiunge ulteriori modi per aggiungere una relazione molti-a-molti.

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

set è una novità:

>>> new_list = [obj1, obj2, obj3]
>>> e.related_set.set(new_list)

2
setè sempre stato lì, penso. È solo che ha funzionato attraverso l'incarico e.related_set = new_listnei vecchi Djangos è equivalente e.related_set.set(new_list). Hanno appena capito che "esplicito è meglio che implicito".
DylanYoung

1
Attenzione: per essere concisi, impostare elimina tutti i modelli associati esistenti. Quindi, se vuoi aggiungere un elenco di nuovi oggetti e vuoi mantenere intatto quello esistente, usa aggiungi (* newlist)
Tasawar Hussain,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.