Skip to content

Instantly share code, notes, and snippets.

@luzfcb
Forked from glasslion/generic_relations.py
Last active August 29, 2015 14:23
Show Gist options
  • Save luzfcb/4dd1b4466723db1ae392 to your computer and use it in GitHub Desktop.
Save luzfcb/4dd1b4466723db1ae392 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