9đź‘Ť
At the time of writing, Django latest version was 1.2
But it needs some additional elements to work.
You need to assign a custom models.Manager object for each animal model which will call its own custom QuerySet object.
Basically, instead of returning Animal
instances (this is what you get), SubclassingQuerySet
calls as_leaf_class()
method to check if item’s model is Animal
or not – if it is, then just return it, otherwise perform search in its model context. Thats it.
#models.py
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.as_leaf_class()
return result
def __iter__(self):
for item in super(SubclassingQuerySet, self).__iter__():
yield item.as_leaf_class()
class AnimalManager(models.Manager):
def get_query_set(self): # Use get_queryset for Django >= 1.6
return SubclassingQuerySet(self.model)
class Animal(models.Model):
name = models.CharField(max_length=100)
content_type = models.ForeignKey(ContentType, editable=False, null=True)
objects = AnimalManager()
def __unicode__(self):
return "Animal: %s" % (self.name)
def save(self, *args, **kwargs):
if not self.content_type:
self.content_type = ContentType.objects.get_for_model(self.__class__)
super(Animal, self).save(*args, **kwargs)
def as_leaf_class(self):
content_type = self.content_type
model = content_type.model_class()
if model == Animal:
return self
return model.objects.get(id=self.id)
class Sheep(Animal):
wool = models.IntegerField()
objects = AnimalManager()
def __unicode__(self):
return 'Sheep: %s' % (self.name)
Testing:
>>> from animals.models import *
>>> Animal.objects.all()
[<Sheep: Sheep: White sheep>, <Animal: Animal: Dog>]
>>> s, d = Animal.objects.all()
>>> str(s)
'Sheep: White sheep'
>>> str(d)
'Animal: Dog'
>>>
3đź‘Ť
You might be successful by accessing {{ animal.sheep }} – the model inheritance is not what you would think, there is a heavy metaclass machinery under the cover that “converts” such inheritance into an implicit OneToOneField relationship.
- Issue with createsuperuser when implementing custom user model
- How to configure Apache to run ASGI in Django Channels? Is Apache even required?
- 'AnonymousUser' object is not iterable
- Django South migration conflict while working in a team
1đź‘Ť
There’s a very simple django app called django-polymorphic-models that helps you with that. It will provide you with a downcast()
method on the model itself that will return your “child” object, as well as a special queryset class to deal with these problems!
It can also be very useful to know that using select_related()
on the base model’s queryset will also get the child objects, that are referenced through a OneToOneField
, which can be a nice performance boost sometimes!
- How to make trailing slash optional in django
- How to track the progress of individual tasks inside a group which forms the header to a chord in celery?
- Fatal error: libmemcached/memcached.h: no such file or directory
1đź‘Ť
I would recommend using Django proxy models, e.g. if you have the base model Animal which is subclassed by Sheep and Horse you would use:
class Animal(models.Model):
pass
class Horse(Animal):
class Meta(Animal.Meta):
proxy = True
class Sheep(Animal):
class Meta(Animal.Meta):
proxy = True
This is not what Proxy models are intended for but I wouldn’t recommend using Django polymorphism unless you need the benefits of storing model specific data in separate tables. If you have a hundred horse specific attributes that all have default values stored in the database, and then only have 2 horse objects, but have a million sheep, you have a million rows, each with a hundred horse specific values you don’t care about, but again this is only really relevant if you don’t have enough disk space, which is unlikely. When polymorphism works well it’s fine, but when it doesn’t it’s a pain.
- Pip / virtualenv / django installation issue
- Django serialize multiple objects in one call
- What is the difference between syncdb and migrate?
- Django: Custom User Model fields not appearing in Django admin
- Show a successful message with Class Based Views
0đź‘Ť
You should check this answer: https://stackoverflow.com/a/929982/684253
The solution it proposes is similar to using django-polymorphic-models, that was already mentioned by @lazerscience. But I’d say django-model-utils is a little bit better documented than django-polymorphic, and the library is easier to use. Check the readme under “Inheritance Manager”: https://github.com/carljm/django-model-utils/#readme
- How to run multiple Django sites on Nginx and uWSGI?
- Django's annotate Count with division returns integer instead of float
- Django manage.py runserver verbosity
- Django + uwsgi + nginx + SSL
- Cannot install "psycopg2" on Windows 10 with Python 3.8