Polymorphic models implementation for django
Project description
A django application that provides a simple way to retrieve models type casted to their original ContentType.
Installation
>>> pip install django-polymodels
Make sure 'django.contrib.contenttypes' and 'polymodels' are in your INSTALLED_APPS
INSTALLED_APPS += ('django.contrib.contenttypes', 'polymodels')
Usage
Subclass PolymorphicModel, an abstract model class.
from django.db import models from polymodels.models import PolymorphicModel class Animal(PolymorphicModel): name = models.CharField(max_length=255) def __unicode__(self): return self.name class Mammal(Animal): pass class Dog(Mammal): pass class Reptile(Animal): pass class Snake(Reptile): class Meta: proxy = True
Objects are created the same way as usual and their associated ContentType is 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 retreive type casted instances from the Animal.objects manager you just have to use the select_subclasses method.
>>> 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 to select_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 the select_subclasses call.
>>> 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 the exclude_subclasses method.
>>> Mammal.objects.all() [<Mammal: mammal>]
Each instance of PolymorphicModel has a type_cast method that knows how to convert itself to the correct ContentType.
>>> animal_snake = Animal.objects.get(pk=snake.pk) <Animal: snake> >>> animal_snake.type_cast() <Snake: snake> >>> animal_snake.type_cast(Reptile) <Reptile: snake>
If the PolymorphicModel.content_type fields conflicts with one of your existing fields you just have to subclass polymodels.models.BasePolymorphicModel and specify which field polymodels should use instead by defining a CONTENT_TYPE_FIELD attribute on your model. This field must be a ForeignKey to ContentType.
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 works
Under the hood select_subclasses calls seleted_related to avoid unnecessary queries and filter if you pass some classes to it. On queryset iteration, the fetched instanced are converted to their correct type by calling BasePolymorphicModel.type_cast. Note that those lookups are cached on class creation to avoid computing them on every single query.
Contribute
If you happen to encounter a bug or would like to suggest a feature addition please file an issue or create a pull request containing tests.
Credits
Inspired by a post of Jeff Elmores.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for django-polymodels-1.4.6a2.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8ffced9abc8113d9ef8a412278f0d6e99bb99ab33cbffa9839fc34edf5fee305 |
|
MD5 | 3aa0e7ebac5f644ec536378cac4f6f49 |
|
BLAKE2b-256 | 850a1f06d1b8d5f92b24c4a54646bc20a2b01a6e6e65c384b4097e9dca89b777 |
Hashes for django_polymodels-1.4.6a2-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 199ec9448b82c2fb72e7aa86b199734870c489ae282eb786e117066942d68cc7 |
|
MD5 | 722c5a3ffcb8926e0e6126de8895866c |
|
BLAKE2b-256 | 004f894ba1b6b42d31aec8a5447e602805b83e832cfa11fad8ef903b4d7e445a |