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')
我正在选择一堆声明,我希望相关的证明可以被拉入而不是单独查询。
答案 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表名。 如果您需要多个字段,请在字典中指定每个字段。