Django:select_related和GenericRelation

时间:2010-05-30 17:10:23

标签: django django-orm

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')

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

3 个答案:

答案 0 :(得分:17)

没有内置方法可以做到这一点。但我发布了一种模拟select_related关于通用关系on my blog的技术。


博客内容摘要:

我们可以使用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将检查的属性,并填充if   必要的,如果你直接调用x.content_object。通过预先填充   它,我们确保Django永远不需要打电话给个人   查找 - 实际上我们正在做的是实现一种   select_related()用于泛型关系。

答案 1 :(得分:3)

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

答案 2 :(得分:3)

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

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

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