Skip to content

Instantly share code, notes, and snippets.

@glasslion
Created August 16, 2013 07:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save glasslion/6247958 to your computer and use it in GitHub Desktop.
Save glasslion/6247958 to your computer and use it in GitHub Desktop.
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/ and justinfx's gist cache_generics.py : https://gist.github.com/justinfx/3095246#file-cache_generics-py Su…
'''
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/
and
justinfx's gist cache_generics.py :
https://gist.github.com/justinfx/3095246#file-cache_generics-py
Supports customized object_id_field and GenericForeignKey name.
'''
from operator import attrgetter
from django.contrib.contenttypes.models import ContentType
def cache_generic_content_types(queryset, object_id_field='object_id', content_type_fk='content_object'):
"""
Django does not support select_related on generic foreign key. Thus some
ORM actions may trigger N+M querys(N is item number of the queryset and
M is the item number of the content type). This function will cache content
and reduce N+M querys to 2 querys.
object_id_field: see https://docs.djangoproject.com/en/1.3/ref/contrib/contenttypes/#django.contrib.contenttypes.generic.GenericRelation
content_type_fk: the name of GenericForeignKey which linked to content type
"""
get_object_id = attrgetter(object_id_field)
generics = {}
for item in queryset:
if get_object_id(item) is not None:
generics.setdefault(item.content_type_id, set()).add(get_object_id(item))
content_types = ContentType.objects.in_bulk(generics.keys())
relations = {}
for ct, fk_list in generics.iteritems():
ct_model = content_types[ct].model_class()
relations[ct] = ct_model.objects.in_bulk(list(fk_list))
for item in queryset:
try:
cached_val = relations[item.content_type_id][get_object_id(item)]
except KeyError:
cached_val = None
setattr(item, '_%s_cache' % content_type_fk, cached_val)
return queryset
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment