Get derived model instance

 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
from django.db.models import Manager
from django.db.models.query import QuerySet
from django.db.models.fields.related import SingleRelatedObjectDescriptor


class _DerivedNamesMixin(object):
    def _get_derived_names(self):
        return [k for k, v in self.model.__dict__.iteritems()
                if isinstance(v, SingleRelatedObjectDescriptor)
                and issubclass(v.related.model, self.model)]


class DerivedQuerySet(_DerivedNamesMixin, QuerySet):
    def iterator(self):
        prefetched = super(DerivedQuerySet, self).select_related(
            *self._get_derived_names())
        for obj in super(DerivedQuerySet, prefetched).iterator():
            yield self.__get_derived(obj)

    def __get_derived(self, instance):
        from django.core.exceptions import ObjectDoesNotExist
        for derived_name in self._get_derived_names():
            try:
                return getattr(instance, derived_name)
            except ObjectDoesNotExist:
                pass
        return instance


class DerivedManager(_DerivedNamesMixin, models.Manager):
    def get_query_set(self, *args, **kwargs):
        return DerivedQuerySet(self.model, using=self._db).select_related(
            *self._get_derived_names())

More like this

  1. SuperChoices by willhardy 5 years, 5 months ago
  2. sort_by_id_sequence by simon 5 years, 11 months ago
  3. Pagination/Filtering Alphabetically by zain 5 years, 1 month ago
  4. Django model objects and querysets dehydration/hydration by Kronuz 2 years, 5 months ago
  5. Yet another SQL debugging facility by miracle2k 6 years, 8 months ago

Comments

arthur (on September 18, 2013):

The model definition example should probably be:

class BaseModel(models.Model):
    foo = models.IntegerField(null=True)

    derived = DerivedManager()

class FirstChild(BaseModel):
    bar = models.IntegerField(null=True)

class SecondChild(BaseModel):
    baz = models.IntegerField(null=True)

(FirstChild and SecondChild should inherit from BaseModel, not models.Model)

Otherwise, looks very useful, thanks!

#

(Forgotten your password?)