11

基本クラスのクエリから返された後、Django データベース オブジェクトの「実際の」クラスを特定する方法はありますか?

たとえば、これらのモデルがある場合...

class Animal(models.Model):
    name= models.CharField(max_length=128)

class Person(Animal):
    pants_size = models.IntegerField(null=True)

class Dog(Animal):
    panting_rate = models.IntegerField(null=True)

そして、これらのインスタンスを作成します...

Person(name='Dave').save()
Dog(name='Mr. Rufflesworth').save()

のようなクエリを実行すると、 のインスタンスと のインスタンスではなく、Animal.objects.all()2 つのインスタンスになります。どのインスタンスがどのタイプであるかを判断する方法はありますか?AnimalPersonDog


参考:私はすでにこれをやろうとしました...

isinstance(Animal.objects.get(name='Dave'),Person) # <-- Returns false!

しかし、それはうまくいかないようです。

4

4 に答える 4

11

私は過去に同様の問題を抱えていましたが、この答えのおかげで最終的に満足のいく解決策を見つけました。

クラスを格納し、それを親クラスに継承させる抽象クラスを実装することにより、各親クラスインスタンスを実際の型にキャストできます。(その回答で使用されている抽象クラスは、django-model-utilsで利用できるようになりました。)

たとえば、抽象クラスを定義したら(または、django-model-utilsを使用している場合)、次のようにするだけです。

class Animal(InheritanceCastModel):
    name= models.CharField(max_length=128)

class Person(Animal):
    pants_size = models.IntegerField(null=True)

class Dog(Animal):
    panting_rate = models.IntegerField(null=True)

それを使用するのは簡単です:

>>> from zoo.models import Animal, Person, Dog
>>> Animal(name='Malcolm').save()
>>> Person(name='Dave').save()
>>> Dog(name='Mr. Rufflesworth').save()
>>> for obj in Animal.objects.all():
...     print obj.name, type(obj.cast())
...
Malcolm <class 'zoo.models.Animal'>
Dave <class 'zoo.models.Person'>
Mr. Rufflesworth <class 'zoo.models.Dog'>
于 2011-03-08T10:06:20.480 に答える
9

はい、これは可能です。自動逆OneToOneFieldリレーションを照会するだけです。例えば:

a = Animal.objects.select_related('person', 'dog')[0]
a = a.person or a.dog or a # whichever is not None
print a
print isinstance(a, Person)

here を使用すると、サブクラスの属性/関係にアクセスするときselect_relatedに例外をテストする必要がなく、単一のクエリでこれを実行できます。DoesNotExist

よりエレガントで長期的なソリューションについては、こちらの回答とdjango-model-utilsも参照してください。InheritanceManager

Django のコアでこれを簡単にする方法を検討しています。

于 2011-03-07T23:24:39.067 に答える
2

これを解決するには、django-polymorphic の使用を検討してください。継承されたモデルの自動ダウンキャストをサポートし、ForeignKeys/ManyToMany フィールドで動作し、管理者にも統合されます。

于 2013-05-20T21:41:40.537 に答える