Django: select_related and GenericRelation

前端 未结 3 436
一个人的身影
一个人的身影 2020-12-09 00:01

Does select_related work for GenericRelation relations, or is there a reasonable alternative? At the moment Django\'s doing individual sql calls for each item in my queryset

相关标签:
3条回答
  • 2020-12-09 00:25

    Looks like select_related and GRs don't work together. I guess you could write some kind of accessor for Claim that gets them all via the same query. This post gives you some pointers on raw SQL to get generic objects, if you need them

    0 讨论(0)
  • 2020-12-09 00:31

    you can use .extra() function to manually extract fields :

    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. proof_proof is the SQL table name for Proof model. If you need more than one field, specify each of them in the dictionnary.

    0 讨论(0)
  • 2020-12-09 00:36

    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.


    Blog content summarized:

    We can use Django's _content_object_cache field to essentially create our own select_related for generic relations.

    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. Then, we do one query per content type, again using in_bulk, to get all the actual object.

    Finally, we simply set the relevant object to the _content_object_cache field of the source item. 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. 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.

    0 讨论(0)
提交回复
热议问题