Django: select_related and GenericRelation

前端 未结 3 454
一个人的身影
一个人的身影 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: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.

提交回复
热议问题