【问题标题】:How to batch update a django M2M-relationship with intermediate model?如何批量更新与中间模型的 django M2M 关系?
【发布时间】:2016-09-19 10:03:42
【问题描述】:

我有两个模型和一个中间模型(简化示例):

class Book(model.Model):
    title=models.CharField(max_length=255)
    owner=models.ManyToManyField(User, through="Ownership")

class Ownership(models.Model):
    user=models.ForeignKey(User)
    book=models.ForeignKey(Book)
    read=models.BooleanField()

现在我已经有很多 Book 对象并且想要添加所有现有的一对一用户。

目前我只看到一个管理器 API,它要么构造 Ownership 模型,要么将 Ownership 对象(可能不保存?)添加到 Book。这意味着对所有 Book 对象使用 python 循环,然后为每个对象构造一个 Ownership 对象。

有没有更高效的解决方案,比如Book.objects.update(owner=user, read=True),在django API中实际上是允许的?

请不要介意小的语法问题,代码是编造的,因为实际代码要长得多。

【问题讨论】:

  • 也许您的意思是 ManyToManyFieldthrough 而不是 Many2Manyintermediate
  • Gotcha,只是将代码编写为伪代码;-)。当然,实际代码具有正确的名称。问题是如何批量更新它们(最好在后端产生一个大 SQL 查询)。

标签: django database orm


【解决方案1】:

您可以使用bulk_create() 在一个查询中保存多个对象:

# First create an unsaved Ownership object for each book
objs = [Ownership(user=user, book=book, read=True) for book in Book.objects.all()]
# Save all ownerships in one query
Ownership.objects.bulk_create(objs)

【讨论】:

    【解决方案2】:

    如果不创建 Ownership 对象,我想不出办法,但您可以使用 bulk_create 将它们提交到数据库:

    Ownership.objects.bulk_create(
        Ownership(read=True, user=user, book=book)
        for book in Book.objects.all())
    

    您可以通过遍历书籍 id 来避免创建 Book 对象:

    Ownership.objects.bulk_create(
        Ownership(read=True, user=user, book_id=book_id)
        for book_id in Book.objects.values_list('pk', flat=True))
    

    bulk_create 有一个batch_size 选项,但它无助于拆分所有权对象的创建,因此如果需要创建许多对象,则会使用大量内存。但是,我们可以自己拆分它们以控制内存:

    count = Book.objects.count()
    batch_size = 10**5
    for i in range(0, count, batch_size):
        result = Ownership.objects.bulk_create(
            Ownership(read=True, user=user, book_id=book_id)
            for book_id in Book.objects.values_list('pk', flat=True)[i:min(i + batch_size, count)])
    

    【讨论】:

    • 谢谢,bulk_create 听起来不错。我认为没有办法以某种方式一一创建所有权,因为它们需要添加,而不仅仅是更新。我希望bulk_create 比 python 循环更有效。
    猜你喜欢
    • 2023-02-17
    • 2014-03-02
    • 2012-07-28
    • 2018-08-25
    • 1970-01-01
    • 2010-10-22
    • 2013-02-10
    • 2012-08-26
    • 1970-01-01
    相关资源
    最近更新 更多