简体   繁体   English

Django:select_related和GenericRelation

[英]Django: select_related and GenericRelation

Does select_related work for GenericRelation relations, or is there a reasonable alternative? select_related是否适用于GenericRelation关系,还是有合理的替代方案? At the moment Django's doing individual sql calls for each item in my queryset, and I'd like to avoid that using something like select_related. 目前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')

I'm selecting a bunch of Claims, and I'd like the related Proofs to be pulled in instead of queried individually. 我正在选择一堆声明,我希望将相关的Proofs拉入而不是单独查询。

There isn't a built-in way to do this. 没有内置的方法来做到这一点。 But I've posted a technique for simulating select_related on generic relations on my blog . 但我发布了一种在我的博客上模拟一般关系上的 select_related的技术。


Blog content summarized: 博客内容汇总:

We can use Django's _content_object_cache field to essentially create our own select_related for generic relations. 我们可以使用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])

Here we get all the different content types used by the relationships in the queryset, and the set of distinct object IDs for each one, then use the built-in in_bulk manager method to get all the content types at once in a nice ready-to-use dictionary keyed by ID. 在这里,我们获取查询集中关系使用的所有不同内容类型,以及每个内容的不同对象ID的集合,然后使用内置的in_bulk管理器方法一次性获取所有内容类型 - 使用ID键入的字典。 Then, we do one query per content type, again using in_bulk, to get all the actual object. 然后,我们为每个内容类型执行一次查询,再次使用in_bulk,以获取所有实际对象。

Finally, we simply set the relevant object to the _content_object_cache field of the source item. 最后,我们只需将相关对象设置为源项的_content_object_cache字段即可。 The reason we do this is that this is the attribute that Django would check, and populate if necessary, if you called x.content_object directly. 我们这样做的原因是,如果您直接调用x.content_object,这是Django将检查的属性,并在必要时填充。 By pre-populating it, we're ensuring that Django will never need to call the individual lookup - in effect what we're doing is implementing a kind of select_related() for generic relations. 通过预先填充它,我们确保Django永远不需要调用单独的查找 - 实际上我们正在做的是为泛型关系实现一种select_related()。

Looks like select_related and GRs don't work together . 看起来像select_related和GRs不能一起工作 I guess you could write some kind of accessor for Claim that gets them all via the same query. 我想你可以为Claim写一些访问器,通过相同的查询获取它们。 This post gives you some pointers on raw SQL to get generic objects, if you need them 这篇文章为您提供了一些关于原始SQL的指针 ,以便在需要时获取通用对象

you can use .extra() function to manually extract fields : 您可以使用.extra()函数手动提取字段:

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

The .filter() will do the join, the .extra() will pull a field. .filter()将执行连接,.extra()将提取字段。 proof_proof is the SQL table name for Proof model. proof_proof是Proof模型的SQL表名。 If you need more than one field, specify each of them in the dictionnary. 如果您需要多个字段,请在字典中指定每个字段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM