以下是一个例子:
如果我有这些课程
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))
但我发现这个解决方案并不优雅高效。有没有循环的解决方案吗?
答案 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()
方法,并立即添加整个集合。