Skip to content

Instantly share code, notes, and snippets.

@tyaslab
Last active August 29, 2015 14:18
Show Gist options
  • Save tyaslab/c1b1fc95527ebf19af95 to your computer and use it in GitHub Desktop.
Save tyaslab/c1b1fc95527ebf19af95 to your computer and use it in GitHub Desktop.
Simple Django Polymorphic
# http://stackoverflow.com/questions/5360995/polymorphism-in-django-models
# http://stackoverflow.com/questions/929029/how-do-i-access-the-child-classes-of-an-object-in-django-without-knowing-the-nam/929982#929982
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.db.models.query import QuerySet
class SubclassingQuerySet(QuerySet):
def __getitem__(self, k):
result = super(SubclassingQuerySet, self).__getitem__(k)
if isinstance(result, models.Model):
return result.cast()
return result
def __iter__(self):
for item in super(SubclassingQuerySet, self).__iter__():
yield item.cast()
class PolymorphicManager(models.Manager):
def get_queryset(self):
return SubclassingQuerySet(self.model)
class PolymorphicModel(models.Model):
"""
An abstract base class that provides a ``real_type`` FK to ContentType.
For use in trees of inherited models, to be able to downcast
parent instances to their child types.
"""
real_type = models.ForeignKey(ContentType, editable=False)
objects = PolymorphicManager()
def save(self, *args, **kwargs):
if not self.id:
self.real_type = self._get_real_type()
super(PolymorphicModel, self).save(*args, **kwargs)
def _get_real_type(self):
return ContentType.objects.get_for_model(type(self))
def cast(self):
return self.real_type.get_object_for_this_type(pk=self.pk)
class Meta:
abstract = True
### EXAMPLE MODELS ###
# Classified
# Vehicle
# Motor
# Car
# Fashion
### END OF EXAMPLE MODELS ###
class Classified(PolymorphicModel):
name = models.CharField(max_length=200)
class Vehicle(Classified):
year_assembled = models.CharField(max_length=5)
class Fashion(Classified):
color = models.CharField(max_length=50)
class Motor(Vehicle):
pass
class Car(Vehicle):
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment