'''
Cache the generic relation field of all the objects 
in the queryset, using larger bulk queries ahead of time.

Improved from original by Daniel Roseman:
http://blog.roseman.org.uk/2010/02/22/django-patterns-part-4-forwards-generic-relations/

Adapted for egonomy project by Thibaut Cavalie
'''
from django.contrib.contenttypes.models import ContentType

import logging
logger = logging.getLogger(__name__)

def cache_generics(queryset):
    generics = {}
    for item in queryset:
        if item.object_id is not None:
            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.iteritems():
        ct_model = content_types[ct].model_class()
        # In our case relations[ct] = ct_model.objects.in_bulk(list(fk_list))
        # is not enough because we need select_related for both images and fragments.
        # We test str(content_types[ct])=="fragment" because it avoids import Image and Fragment just to test contenttypes.
        # So we can import this function in models.py.
        if str(content_types[ct]) == "image":
            relations[ct] = ct_model.objects.select_related('info', 'metadata').in_bulk(list(fk_list))
        elif str(content_types[ct]) == "fragment":
            relations[ct] = ct_model.objects.select_related('image', 'image__info', 'image__metadata','author').in_bulk(list(fk_list))
        else:
            relations[ct] = ct_model.objects.in_bulk(list(fk_list))

    for item in queryset:
        try:
            try:
                item.object_id = int(item.object_id)
            except:
                pass
            cached_val = relations[item.content_type_id][item.object_id]
        except KeyError:
            cached_val = None
        setattr(item, '_content_object_cache', cached_val)  