【问题标题】:Django efficiency: ManyToManyFieldDjango 效率:ManyToManyField
【发布时间】:2014-03-05 00:12:42
【问题描述】:

在 Django 中,假设我有一个经常被调用的函数:

def blockUser(id_to_block, user):
   to_block = Usr.objects.get(pk=id_to_block)
   user.blocked.add(to_block)
   user.save()

其中userUsr 类型,是使用models.Model 制作的自定义类,blocked 是ManyToManyField。

按照我的阅读方式,Django 将从数据库中获取to_block,然后将to_block 添加到user.blocked,访问数据库两次。由于 ManyToManyField 只是一个带有 from_idto_id 的表,而且我已经知道这两个 id,我可以只通过一个数据库访问来完成它吗?

我的问题是,鉴于to_block 没有在其他任何地方使用这一事实,Django 真的会为此进行两次数据库查询吗?如果是这样,我如何通过一个数据库查询来实现这一目标?

非常感谢!

【问题讨论】:

    标签: django


    【解决方案1】:

    您无需获取 to_block 对象即可将其添加到阻塞的 ManyToManyField。使用主键也可以。 此外,您不需要在添加关系后调用用户对象上的保存。

    def blockUser(id_to_block, user):
       user.blocked.add(id_to_block)
    

    尽管如此,这会执行 2 个 sql 查询。

    • 首先检查用户是否已经屏蔽了 to_block 用户。
    • 然后它执行实际插入。

    如果您想避免完整性检查,您可以直接创建中间模型的实例。

    def blockUser(id_to_block, user):
        # create an instance of the intermediate model
        block_entry = Usr.blocked.through(user_id=user.id, blocked_id=id_to_block)    
        try:
            with transaction.commit_on_success():
                block_entry.save()
        except IntegrityError:
            pass
    

    blocked_id 可能不是正确的字段名称。

    【讨论】:

      【解决方案2】:

      你可以使用 Django 的select_related()。来自文档:

      这是一种性能提升器,可导致(有时)更大 查询,但意味着以后使用外键关系不会 需要数据库查询

      更新

      对于 ManyToMany 字段,请使用 prefetch_related()。与select_related() 相同的主体。来自文档:

      这允许它预取多对多和多对一的对象,这 不能使用 select_related 来完成,除了外键 以及 select_related 支持的一对一关系。

      【讨论】:

      猜你喜欢
      • 2012-01-12
      • 2011-12-24
      • 2013-02-24
      • 1970-01-01
      • 1970-01-01
      • 2012-02-09
      • 2019-08-10
      • 2014-09-15
      • 1970-01-01
      相关资源
      最近更新 更多