【问题标题】:How to add multiple objects to ManyToMany relationship at once in Django ?如何在 Django 中一次将多个对象添加到 ManyToMany 关系?
【发布时间】:2011-06-24 23:24:13
【问题描述】:

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

* TypeError: unhashable type: 'list'

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

【问题讨论】:

    标签: django list manytomanyfield


    【解决方案1】:

    使用:object.m2mfield.add(*items),如documentation 中所述:

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

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

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

    add(*[obj1, obj2, obj3])
    

    附录:

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

    【讨论】:

    • 如果您查看管理器,它只会对对象执行 for 循环并调用它们的保存。
    • shell 的一个简短实验表明@sdolan 实际上(当前)是不正确的。 IE。当我查看生成的 SQL 时,我只看到一个插入语句: INSERT INTO app_one_twos (one_id, two_id) VALUES (1, 1), (1, 2), (1, 3), (1, 4);这是在 Django 1.4 中。
    • @KlaasvanSchelven:我不记得通过生成的 sql 进行了测试,但根据我的评论,我很确定我只是看了一眼源代码。请记住,这是 2 年前的事了,所以我希望事情已经优化了一点。
    • @sdolan 不,他们没有改进它。我只是在测试它。
    • 有什么方法可以按值(例如 id)做到这一点?有时您没有对象列表,而是对象值列表(即 id)?而不是循环遍历并将所有对象抓取到另一个列表中......
    【解决方案2】:

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

    例子

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

    发件人:Insert queryset results into ManytoManyfield

    【讨论】:

    • 这执行两个查询而不是一个:(
    • 请注意,您不需要将其转换为列表。直接添加(*permissions)即可。
    • 谢谢兄弟。这真的对我有帮助。我试图通过subject = Subject.objects.filter(connect_class=class_list)。我做了student_data.subject.add(*subject),它奏效了。
    【解决方案3】:

    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)
    

    【讨论】:

    • set 我想一直都在那里。只是它过去在旧 Django 中通过赋值 e.related_set = new_list 等效于 e.related_set.set(new_list)。他们刚刚意识到“显式胜于隐式”。
    • 注意:为简洁起见,set 删除所有现有的关联模型。因此,如果您想添加新对象列表并希望保持现有对象不变,请使用 add(*newlist)
    • 当您想将记录更新到新集合时,此解决方案非常棒,并且如果对象已经在集合“obj1”中,那么数据库中的记录不会重新创建。
    • 在当前 Django 版本 (3.2.6) 中工作方式相同
    猜你喜欢
    • 2012-12-02
    • 1970-01-01
    • 2016-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-01
    相关资源
    最近更新 更多