Django:select_related和GenericRelation

Par*_*and 8 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')
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*man 17

没有内置的方法来做到这一点.但是我发布了一种在我的博客上模拟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])
Run Code Online (Sandbox Code Playgroud)

在这里,我们获取查询集中关系使用的所有不同内容类型,以及每个内容的不同对象ID的集合,然后使用内置的in_bulk管理器方法一次性获取所有内容类型 - 使用ID键入的字典.然后,我们为每个内容类型执行一次查询,再次使用in_bulk,以获取所有实际对象.

最后,我们只需将相关对象设置为源项的_content_object_cache字段即可.我们这样做的原因是,如果您直接调用x.content_object,这是Django将检查的属性,并在必要时填充.通过预先填充它,我们确保Django永远不需要调用单独的查找 - 实际上我们正在做的是为泛型关系实现一种select_related().


Ste*_*lim 3

看起来select_lated 和 GR 不能一起工作。我想您可以为 Claim 编写某种访问器,通过相同的查询获取它们。这篇文章为您提供了一些关于原始 SQL 的指导,以获取通用对象(如果您需要的话)