web/lib/tagging/generic.py
changeset 11 f236caaceb43
equal deleted inserted replaced
10:7207a5a27b8f 11:f236caaceb43
       
     1 from django.contrib.contenttypes.models import ContentType
       
     2 
       
     3 def fetch_content_objects(tagged_items, select_related_for=None):
       
     4     """
       
     5     Retrieves ``ContentType`` and content objects for the given list of
       
     6     ``TaggedItems``, grouping the retrieval of content objects by model
       
     7     type to reduce the number of queries executed.
       
     8 
       
     9     This results in ``number_of_content_types + 1`` queries rather than
       
    10     the ``number_of_tagged_items * 2`` queries you'd get by iterating
       
    11     over the list and accessing each item's ``object`` attribute.
       
    12 
       
    13     A ``select_related_for`` argument can be used to specify a list of
       
    14     of model names (corresponding to the ``model`` field of a
       
    15     ``ContentType``) for which ``select_related`` should be used when
       
    16     retrieving model instances.
       
    17     """
       
    18     if select_related_for is None: select_related_for = []
       
    19 
       
    20     # Group content object pks by their content type pks
       
    21     objects = {}
       
    22     for item in tagged_items:
       
    23         objects.setdefault(item.content_type_id, []).append(item.object_id)
       
    24 
       
    25     # Retrieve content types and content objects in bulk
       
    26     content_types = ContentType._default_manager.in_bulk(objects.keys())
       
    27     for content_type_pk, object_pks in objects.iteritems():
       
    28         model = content_types[content_type_pk].model_class()
       
    29         if content_types[content_type_pk].model in select_related_for:
       
    30             objects[content_type_pk] = model._default_manager.select_related().in_bulk(object_pks)
       
    31         else:
       
    32             objects[content_type_pk] = model._default_manager.in_bulk(object_pks)
       
    33 
       
    34     # Set content types and content objects in the appropriate cache
       
    35     # attributes, so accessing the 'content_type' and 'object'
       
    36     # attributes on each tagged item won't result in further database
       
    37     # hits.
       
    38     for item in tagged_items:
       
    39         item._object_cache = objects[item.content_type_id][item.object_id]
       
    40         item._content_type_cache = content_types[item.content_type_id]