如何在Django中更新manytomany字段?

时间:2009-07-28 15:02:37

标签: python django

以下是一个例子:

如果我有这些课程

class Author(models.Model):
    name = models.CharField(max_length=45)

class Book(models.Model):
    name = models.CharField(max_length=45)
    authors = models.ManyToManyField(Author)

在数据库中,我有一个名为“George”的作者和另一个名为“Georfe”的作者。最后一个是错误的。所以我想要的是每本书都有“Georfe”作为他的作者之一取代作者“乔治”。

在SQL中很容易做到。如果“George”的id = 3且“Georfe”的id = 7且关系表名称为“author_book”:

UPDATE author_book SET id=3 WHERE id=7;

是否可以使用Django ORM进行此操作?

我找到了一种方法:我通过错误输入作者的所有相关书籍进行循环操作并执行:

book.authors.add(Author.objects.get(id=3))
book.authors.remove(Author.objects.get(id=7))

但我发现这个解决方案并不优雅高效。有没有循环的解决方案吗?

3 个答案:

答案 0 :(得分:19)

注意:此代码将删除错误的'georfe'作者,以及更新图书以指向正确的作者。如果您不想这样做,请使用.remove()作为@ jcdyer的回答提及。

你能做这样的事吗?

george_author = Author.objects.get(name="George")
for book in Book.objects.filter(authors__name="Georfe"):
    book.authors.add(george_author.id)
    book.authors.filter(name="Georfe").delete()

我怀疑如果你有一个明确的表连接两个模型(使用“through”关键字arg)会更容易 - 在这种情况下,你可以直接访问关系表,并且可以只做一个.update(id=george_author.id)就可以了。

答案 1 :(得分:15)

使用自动生成的直通表,您可以执行两步插入和删除操作,这对于提高可读性非常有用。

george = Author.objects.get(name='George')
georfe = Author.objects.get(name='Georfe')

book.authors.add(george)
book.authors.remove(georfe)
assert george in book.authors

如果你有一个明确定义的直通表(authors = models.ManyToManyField(作者,通过= BookAuthors),那么你可以在BookAuthor上明确地改变关系。一个鲜为人知的事实是这个模型已经存在,它是由django生成的如果你想要存储额外的数据(例如特定作者在多作者书中写过的章节),通常你应该只创建一个明确的直通模型。

# This line is only needed without a custom through model.
BookAuthor = Book.authors.through
book_author = BookAuthor.objects.get(author=georfe, book=great_american_novel)
book_author.author = george
book_author.save()
assert george in book.authors

答案 2 :(得分:4)

for django >=1.11 documentation:

>>> b = Blog.objects.get(id=1)
>>> e = Entry.objects.get(id=234)
>>> b.entry_set.add(e) # Associates Entry e with Blog b.
>>> new_list = [obj1, obj2, obj3]
>>> e.related_set.set(new_list)

此方法接受clear参数来控制如何执行该操作。如果为False(默认设置),则使用remove()删除新集合中缺少的元素,仅添加新元素。如果为clear=True,则调用clear()方法,并立即添加整个集合。

和参考:How to .update m2m field in django