は、執筆時点では、Djangoの最新バージョンは1.2
だったが、それが動作するようにいくつかの追加要素を必要とします。
独自のカスタムQuerySetオブジェクトを呼び出す各動物モデルに対して、カスタムmodels.Managerオブジェクトを割り当てる必要があります。
基本的には、代わりにアイテムのモデルがAnimal
であるかどうかをチェックするためにAnimal
インスタンス(これはあなたが得るものです)、SubclassingQuerySet
通話as_leaf_class()
方法を返す - それがある場合は、それを返すそうでない場合は、そのモデルのコンテキストで検索を実行します。それでおしまい。
#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)
テスト:
>>> 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'
>>>
このユースケース用に設計された[django-polymorphic](https://github.com/chrisglass/django_polymorphic)をご覧ください。モデルがforeignkeys、ManyToManyFieldsなどでフェッチされたときにも機能します。 – vdboor
しないでください! :P私のテイクを下に見てください:http://stackoverflow.com/a/20353347/539490 – AJP