【问题标题】:Django: select_related and GenericRelationDjango:select_related 和 GenericRelation
【发布时间】:2011-02-25 17:48:43
【问题描述】:

select_related 是否适用于 GenericRelation 关系,或者是否有合理的替代方案?目前 Django 正在为我的查询集中的每个项目执行单独的 sql 调用,我想避免使用类似 select_related 的东西。

class Claim(models.Model):
    proof = generic.GenericRelation(Proof)


class Proof(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

我正在选择一堆声明,我希望将相关的证明拉入而不是单独查询。

【问题讨论】:

    标签: django django-orm


    【解决方案1】:

    没有内置的方法可以做到这一点。但我已经发布了一种在泛型关系on my blog 上模拟select_related 的技术。


    博客内容汇总:

    我们可以使用 Django 的 _content_object_cache 字段本质上为泛型关系创建我们自己的 select_related

    generics = {}
    for item in queryset:
        generics.setdefault(item.content_type_id, set()).add(item.object_id)
    
    content_types = ContentType.objects.in_bulk(generics.keys())
    
    relations = {}
    for ct, fk_list in generics.items():
        ct_model = content_types[ct].model_class()
        relations[ct] = ct_model.objects.in_bulk(list(fk_list))
    
    for item in queryset:
        setattr(item, '_content_object_cache', 
                relations[item.content_type_id][item.object_id])
    

    这里我们得到了关系使用的所有不同的内容类型 在查询集中,以及每个对象的一组不同的对象 ID,然后 使用内置 in_bulk 管理器方法获取所有内容类型 立即在一个由 ID 键入的漂亮的即用型字典中。然后,我们做一个 再次使用 in_bulk 查询每个内容类型,以获取所有实际的 对象。

    最后,我们简单地将相关对象设置为 源项目的 _content_object_cache 字段。我们这样做的原因是这是 Django 会检查的属性,如果 必要的,如果您直接调用 x.content_object。通过预填充 它,我们确保 Django 永远不需要打电话给个人 查找 - 实际上我们正在做的是实现一种 select_related() 用于泛型关系。

    【讨论】:

      【解决方案2】:

      您可以使用 .extra() 函数手动提取字段:

      Claims.filter(proof__filteryouwant=valueyouwant).extra(select={'field_to_pull':'proof_proof.field_to_pull'})
      

      .filter() 将进行连接,.extra() 将拉出一个字段。 proof_proof 是 Proof 模型的 SQL 表名。 如果您需要多个字段,请在字典中指定每个字段。

      【讨论】:

        【解决方案3】:

        看起来像select_related and GRs don't work together。我想您可以为 Claim 编写某种访问器,通过相同的查询获取它们。这个post gives you some pointers 在原始 SQL 上获取通用对象,如果你需要的话

        【讨论】:

          猜你喜欢
          • 2010-11-06
          • 2010-11-26
          • 2012-02-03
          • 1970-01-01
          • 1970-01-01
          • 2015-03-01
          • 1970-01-01
          • 2020-07-24
          • 1970-01-01
          相关资源
          最近更新 更多