如何在Django中一次将多个对象添加到ManyToMany关系?


183

基于Django文档,我应该能够一次传递多个对象以将其添加到多对多关系中,但是我得到了

* TypeError:无法散列的类型:“列表”

当我尝试传递列表中的django queryset时。传递Queryset或ValuesListQueryset似乎也失败。有没有比使用for循环更好的方法?

Answers:


317

用途:object.m2mfield.add(*items)文档中所述:

add() 接受任意数量的参数,而不是它们的列表。

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

要将列表扩展为参数,请使用 *

add(*[obj1, obj2, obj3])

附录:

Django不会要求obj.save()每个项目,而是使用bulk_create()


如果您查看管理器,它只是对对象进行for循环,并调用保存在对象上。
山姆·多兰

3
从外壳进行的简短实验表明,@ sdolan实际上(当前)是错误的。即,当我查看生成的SQL时,我只看到一条插入语句:INSERT INTO app_one_twos(one_id,two_id)VALUES(1、1),(1、2),(1、3),(1、4);这是在Django 1.4中。
克拉斯·范·舍夫

@KlaasvanSchelven:我不记得通过生成的sql对此进行测试,但是基于我的评论,我很确定自己只是看了一下源代码。请记住,这是两年多以前的事了,所以我希望事情有所优化。
Sam Dolan 2013年

1
@sdolan不,他们没有改善它。我只是在测试。
Saransh Mohapatra,

1
有什么办法通过值(例如ID)来做到这一点?有时您没有对象列表,但有对象值列表(即id)?而不是遍历并抓住所有对象进入另一个列表...
DannyMoshe

47

要添加,如果要从查询集中添加它们

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

来自:将查询集结果插入ManytoManyfield


3
这将执行两个查询,而不是一个查询:(
DylanYoung

1
请注意,您无需将其转换为列表。只需直接执行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在旧版Django 中,用于完成分配的工作等效于e.related_set.set(new_list)。他们只是意识到“明确胜于隐含”。
DylanYoung

1
注意:为简洁起见,set会删除所有现有的关联模型。因此,如果您想添加新对象列表并希望保持现有对象不变,请使用add(* newlist)
Tasawar Hussain,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.