人類に知られている唯一の方法は、メタクラス プログラミングを使用することです。
ここに短い答えがあります:
from django.db.models.base import ModelBase
class InheritanceMetaclass(ModelBase):
def __call__(cls, *args, **kwargs):
obj = super(InheritanceMetaclass, cls).__call__(*args, **kwargs)
return obj.get_object()
class Animal(models.Model):
__metaclass__ = InheritanceMetaclass
type = models.CharField(max_length=255)
object_class = models.CharField(max_length=20)
def save(self, *args, **kwargs):
if not self.object_class:
self.object_class = self._meta.module_name
super(Animal, self).save( *args, **kwargs)
def get_object(self):
if not self.object_class or self._meta.module_name == self.object_class:
return self
else:
return getattr(self, self.object_class)
class Dog(Animal):
def make_sound(self):
print "Woof!"
class Cat(Animal):
def make_sound(self):
print "Meow!"
そして望ましい結果:
shell$ ./manage.py shell_plus
From 'models' autoload: Animal, Dog, Cat
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> dog1=Dog(type="Ozzie").save()
>>> cat1=Cat(type="Kitty").save()
>>> dog2=Dog(type="Dozzie").save()
>>> cat2=Cat(type="Kinnie").save()
>>> Animal.objects.all()
[<Dog: Dog object>, <Cat: Cat object>, <Dog: Dog object>, <Cat: Cat object>]
>>> for a in Animal.objects.all():
... print a.type, a.make_sound()
...
Ozzie Woof!
None
Kitty Meow!
None
Dozzie Woof!
None
Kinnie Meow!
None
>>>
それはどのように機能しますか?
- 動物のクラス名に関する情報を保存します - そのために object_class を使用します
- 「プロキシ」メタ属性を削除します - Django で関係を逆にする必要があります (これの悪い面は、子モデルごとに追加の DB テーブルを作成し、そのための追加の DB ヒットを無駄にします。良い面は、いくつかの子モデルに依存するフィールドを追加できることです)。
- アニマルの save() をカスタマイズして、save を呼び出したオブジェクトの object_class にクラス名を保存します。
- object_class にキャッシュされた名前の Model を Django の逆リレーションで参照するには get_object メソッドが必要です。
- この .get_object() の「キャスト」は、Animal モデルの Metaclass を再定義して Animal がインスタンス化されるたびに自動的に行われます。メタクラスは、クラスのテンプレートのようなものです (クラスがオブジェクトのテンプレートであるように)。
Python のメタクラスについて詳しくは、http ://www.ibm.com/developerworks/linux/library/l-pymeta.html をご覧ください。