Djangoで複数のオブジェクトをManyToMany関係に一度に追加する方法は?


185

Djangoドキュメントに基づいて、複数のオブジェクトを一度に渡してmanytomany関係に追加できるはずですが、

* TypeError:ハッシュ化できないタイプ: 'list'

リストにキャストされたdjangoクエリセットを渡そうとすると、QuerysetまたはValuesListQuerysetを渡すことも失敗するようです。forループを使用するよりも良い方法はありますか?

回答:


320

使用:ドキュメントのobject.m2mfield.add(*items)説明に従って:

add() それらのリストではなく、任意の数の引数を受け入れます。

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

そのリストを引数に展開するには、次を使用します *

add(*[obj1, obj2, obj3])

補遺:

Djangoはobj.save()各アイテムを呼び出さずbulk_create()、代わりにを使用します。


マネージャーを見ると、オブジェクトに対してforループを実行し、それらに対してsaveを呼び出します。
Sam Dolan 2011

3
シェルからの短い実験は、@ sdolanが実際に(現在)正しくないことを示しています。つまり、生成されたSQLを見ると、1つの挿入ステートメントしか表示されていません。これはDjango 1.4に含まれています。
Klaas van Schelven 2013年

@KlaasvanSchelven:生成されたsqlを使用してこれをテストしたことは覚えていませんが、私のコメントに基づいて、ソースコードを見ただけだと確信しています。これは2年以上前のことなので、少し最適化されているといいのですが。
Sam Dolan 2013年

1
@sdolanいいえ、改善されていません。私はそれをテストしていました。
サランシュモハパトラ2013

1
これを値(IDなど)で行う方法はありますか?オブジェクトのリストではなく、オブジェクトの値(つまり、ID)のリストがある場合がありますか?すべてのオブジェクトをループして別のリストに
取得するのではなく

48

追加するには、クエリセットから追加する場合

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

From:クエリセットの結果をManytoManyfieldに挿入する


3
これは1つではなく2つのクエリを実行します:(
DylanYoung

2
リストに変換する必要はありません。直接add(* permissions)を実行してください。
BjornW

34

Django 1.9では、多対多の関係を追加する方法が追加されています。

ドキュメント:https : //docs.djangoproject.com/en/dev/ref/models/relations/#django.db.models.fields.related.RelatedManager.set

set 新しい便利さです:

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

2
setいつもそこにいたと思います。e.related_set = new_list古いDjangosで割り当てを処理するために使用されていたのは、と同等e.related_set.set(new_list)です。彼らは、「明示的なものは暗黙的なものよりも優れている」ことに気づきました。
DylanYoung

1
注意:簡潔にするために、setは既存の関連モデルをすべて削除します。したがって、新しいオブジェクトのリストを追加し、既存のオブジェクトをそのままにしたい場合は、add(* newlist)を使用します
Tasawar Hussain
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.