Skip to main content

Polymorphic models implementation for django

Project description

A django application that provides a simple way to retrieve models type casted to their original ContentType.

https://travis-ci.org/charettes/django-polymodels.svg?branch=master https://coveralls.io/repos/charettes/django-polymodels/badge.svg?branch=master&service=github

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 __str__(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.

Note of the author

I’m aware there’s already plenty of existing projects tackling the whole model-inheritance-type-casting-thing such as django-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 of django-mutant’s own mecanism of handling this since I needed it as a standalone app for another project.

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-polymodels-1.7.0.tar.gz (11.7 kB view details)

Uploaded Source

Built Distribution

django_polymodels-1.7.0-py2.py3-none-any.whl (11.0 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file django-polymodels-1.7.0.tar.gz.

File metadata

  • Download URL: django-polymodels-1.7.0.tar.gz
  • Upload date:
  • Size: 11.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/3.7.3 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.59.0 CPython/3.9.2

File hashes

Hashes for django-polymodels-1.7.0.tar.gz
Algorithm Hash digest
SHA256 1a57391bc69b3af080120e830d03ba7fd2fab89b8cfa6e3f6ffa1d33f847e202
MD5 ef7a0abd4aef1c26647dcbbd939eed99
BLAKE2b-256 2cb0b827f5df11ec38a39ca67f3781b6ed5c04df4504a5c339f8589b04146bfa

See more details on using hashes here.

File details

Details for the file django_polymodels-1.7.0-py2.py3-none-any.whl.

File metadata

  • Download URL: django_polymodels-1.7.0-py2.py3-none-any.whl
  • Upload date:
  • Size: 11.0 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/3.7.3 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.59.0 CPython/3.9.2

File hashes

Hashes for django_polymodels-1.7.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 c01e0b578606920d502fe35b4b362cdc4ffc10a8ba92facea785f2b384d1b319
MD5 1cf33f6b361692dce8c84e58737ecb99
BLAKE2b-256 908061a5d08cd2208cd9e699530f37e55dd1d300b8808bfb313d1e7dcc4ca1a0

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page