2010-05-30 58 views
7

是否select_related工作GenericRelation关系,或者是有一个合理的选择?目前Django为我的查询集中的每个项目执行单独的sql调用,并且我想避免使用诸如select_related之类的东西。Django的:select_related和GenericRelation

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

我正在选择一组索赔,并且希望将相关证明拉入单独查询而不是单独查询。

回答

16

没有内置的方式做到这一点。但我已经发布了一种技术来模拟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将检查的属性,并且如果您直接调用x.content_object,则需要填充 。通过预填充 它,我们可以确保Django将永远不需要调用个别 查找 - 这实际上就是我们正在做的是实施一种 select_related()用于一般的关系。

3

你可以使用.extra()函数来手动提取领域:

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

的.filter()会做的加入,.extra()将拉场。 proof_proof是Proof模型的SQL表名。 如果您需要多个字段,请在字典中指定其中的每个字段。