Package: django-polymodels
A django application that provides a simple way to retrieve models type casted
to their originalContentType.Installation>>> pip install django-polymodelsMake sure'django.contrib.contenttypes'and'polymodels'are in
yourINSTALLED_APPSINSTALLED_APPS += ('django.contrib.contenttypes', 'polymodels')UsageSubclassPolymorphicModel, an abstract model class.from django.db import models
from polymodels.models import PolymorphicModel

class Animal(PolymorphicModel):
    name = models.CharField(max_length=255)

    def __str__(self):
        return self.name

class Mammal(Animal):
    pass

class Dog(Mammal):
    pass

class Reptile(Animal):
    pass

class Snake(Reptile):
    class Meta:
        proxy = TrueObjects are created the same way as usual and their associatedContentTypeis saved automatically:>>> animal = Animal.objects.create(name='animal')
>>> mammal = Mammal.objects.create(name='mammal')
>>> reptile = Reptile.objects.create(name='reptile')
>>> snake = Snake.objects.create(name='snake')To retreivetype castedinstances from theAnimal.objectsmanager you just
have to use theselect_subclassesmethod.>>> Animal.objects.select_subclasses()
[<Animal: animal>, <Mammal: mammal>, <Reptile: reptile>, <Snake: snake>]You can also retreive a subset of the subclasses by passing them as arguments toselect_subclass.>>> Animal.objects.select_subclasses(Reptile)
[<Reptile: reptile>, <Snake: snake>]Or directly from subclasses managers.>>> Reptile.objects.select_subclasses(Snake)
[<Snake: snake>]Note that you can also retrieve original results by avoiding theselect_subclassescall.>>> Animal.objects.all()
[<Animal: animal>, <Animal: mammal>, <Animal: reptile>, <Animal: snake>]It’s also possible to select only instances of the model to which the
manager is attached by using theexclude_subclassesmethod.>>> Mammal.objects.all()
[<Mammal: mammal>]Each instance ofPolymorphicModelhas atype_castmethod that knows how
to convert itself to the correctContentType.>>> animal_snake = Animal.objects.get(pk=snake.pk)
<Animal: snake>
>>> animal_snake.type_cast()
<Snake: snake>
>>> animal_snake.type_cast(Reptile)
<Reptile: snake>If thePolymorphicModel.content_typefields conflicts with one of your
existing fields you just have to subclasspolymodels.models.BasePolymorphicModeland specify which fieldpolymodelsshould use instead by defining aCONTENT_TYPE_FIELDattribute on your model.
This field must be aForeignKeytoContentType.from django.contrib.contenttypes.models import ContentType
from django.db import models
from polymodels.models import BasePolymorphicModel

class MyModel(BasePolymorphicModel):
    CONTENT_TYPE_FIELD = 'polymorphic_ct'
    polymorphic_ct = models.ForeignKey(ContentType)How it worksUnder the hoodselect_subclassescallsseleted_relatedto avoid
unnecessary queries andfilterif you pass some classes to it. On queryset
iteration, the fetched instanced are converted to their correct type by callingBasePolymorphicModel.type_cast. Note that those lookups are cached on class
creation to avoid computing them on every single query.Note of the authorI’m aware there’s already plenty of existing projects tackling the wholemodel-inheritance-type-casting-thingsuch asdjango-polymorphic. However
I wanted to implement this feature in a lightweight way: no__metaclass__or__init__overrides while using django’s public API as
much as possible. In the end, this was really just an extraction ofdjango-mutant’s own mecanism of handling this since I needed it as a
standalone app for another project.ContributeIf you happen to encounter a bug or would like to suggest a feature addition
pleasefile an issueorcreate a pull requestcontainingtests.CreditsInspired by apost of Jeff Elmores.