I'm developing django application, and I have such a model structure
class Animal(models.Model):
aul = models.ForeignKey(Aul)
age = models.IntegerField()
def __unicode__(self):
return u'Animal'
class Sheep(Animal):
wool = models.IntegerField()
def __unicode__(self):
return u'Sheep'
And I pass animal_set to template and output every object like this {{ animal }}
. It outputs Animal, but I created objects of sheep type and want to use __unicode__
method of sheep not of animal.
Do polymorphism work in Django models? I have found several answers, but there are snippets of code to write inside models, but I'm interested in native solutions.
Note that the Django ORM is explicitly thread-safe. There are multiple references in the documentation about threaded operation.
A QuerySet is a collection of data from a database. A QuerySet is built up as a list of objects. QuerySets makes it easier to get the data you actually need, by allowing you to filter and order the data.
One of the most powerful features of Django is its Object-Relational Mapper (ORM), which enables you to interact with your database, like you would with SQL. In fact, Django's ORM is just a pythonical way to create SQL to query and manipulate your database and get results in a pythonic fashion.
A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you're storing. Generally, each model maps to a single database table. The basics: Each model is a Python class that subclasses django.db.models.Model .
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'
>>>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With