Manager method for limiting GenericForeignKey queries

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from django.db import models

class GFKManager(models.Manager):
    def relate(self, qs):
        model_map = {}
        item_map = {}
        for item in qs:
            model_map.setdefault(item.content_type, {}) \
                [item.object_id] = item.id
            item_map[item.id] = item
        for ct, items_ in model_map.items():
            for o in ct.model_class().objects.select_related() \
                    .filter(id__in=items_.keys()).all():
                item_map[items_[o.id]].content_object = o
        return qs

Comments

carljm (on September 22, 2008):

This is really nice. A few issues I've observed with it:

1) Referring to item.content_type causes n queries to the ContentType table which bypass its lookup cache. This could easily be addressed by storing the content type id instead and using ContentType.objects.get_for_id, which goes through the cache.

2) This snippet makes assumptions about the names of the content_type and object_id fields used for the GenericForeignKey. It would be more robust to pull this information from the GFK itself.

3) This would be easier to use if it were a method on a queryset of the model with a GFK, so you could just say "StreamItem.objects.filter(...).fetch_generic_relations()" and have it done in one command.

I've posted a version that addresses these issues here.

#

(Forgotten your password?)

You may use Markdown syntax here, but raw HTML will be removed.