- Author:
- werehuman
- Posted:
- September 18, 2013
- Language:
- Python
- Version:
- 1.5
- Score:
- 1 (after 1 ratings)
Get derived model without storing their names or content types in databases. You write only one line, it expands into only one SQL-query (with many LEFT OUTER JOIN's).
Model definition example:
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)
How to use:
>>> f = FirstChild.objects.create()
>>> s = SecondChild.objects.create()
>>> print list(BaseModel.objects.all()
[<BaseModel object 1>, <BaseModel object 2>]
>>> print list(BaseModel.derived.all()
[<FirstChild object 1>, <SecondChild object 2>]
>>> print BaseModel.derived.get(pk=s.pk)
<SecondChild object 2>
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
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
The model definition example should probably be:
(FirstChild and SecondChild should inherit from BaseModel, not models.Model)
Otherwise, looks very useful, thanks!
#
Please login first before commenting.