improved generic foreign key manager

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
from django.db.models.query import QuerySet
from django.db.models import Manager
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.generic import GenericForeignKey

class GFKManager(Manager):
    """
    A manager that returns a GFKQuerySet instead of a regular QuerySet.

    """
    def get_query_set(self):
        return GFKQuerySet(self.model)

class GFKQuerySet(QuerySet):
    """
    A QuerySet with a fetch_generic_relations() method to bulk fetch
    all generic related items.  Similar to select_related(), but for
    generic foreign keys.

    Based on http://www.djangosnippets.org/snippets/984/

    """
    def fetch_generic_relations(self):
        qs = self._clone()

        gfk_fields = [g for g in self.model._meta.virtual_fields
                      if isinstance(g, GenericForeignKey)]
        
        ct_map = {}
        item_map = {}
        
        for item in qs:
            for gfk in gfk_fields:
                ct_id_field = self.model._meta.get_field(gfk.ct_field).column
                ct_map.setdefault(
                    (ct_id_field, getattr(item, ct_id_field)), {}
                    )[getattr(item, gfk.fk_field)] = (gfk.name, item.id)
            item_map[item.id] = item
            
        for (ct_id_field, ct_id), items_ in ct_map.items():
            ct = ContentType.objects.get_for_id(ct_id)
            for o in ct.model_class().objects.select_related().filter(
                id__in=items_.keys()).all():
                (gfk_name, item_id) = items_[o.id]
                setattr(item_map[item_id], gfk_name, o)
                
        return qs

More like this

  1. Improved generic foreign key manager 2 by Nomalz 4 years, 6 months ago
  2. Manager method for limiting GenericForeignKey queries by zerok 5 years, 8 months ago
  3. autocompleter with database query by bbolli 6 years, 9 months ago
  4. Querying on existence of a relationship by ubernostrum 6 years, 8 months ago
  5. Replace model select widget in admin with a readonly link to the related object by ekellner 5 years, 8 months ago

Comments

taddr (on January 22, 2009):

This definitely works. Thank you Carl!

#

(Forgotten your password?)