2011-03-19 6 views
9

私は、Djangoのアプリケーションを開発している、と私は、このようなモデル構造多型ジャンゴでモデル

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' 

を持っていると私はこの{{ animal }}ようなすべてのオブジェクトをテンプレートと出力するanimal_setを渡します。 動物を出力しますが、私は羊の種類のオブジェクトを作成し、__unicode__動物ではない羊の方法を使いたいです。

Djangoモデルで多型が機能しますか?私はいくつかの答えを見つけましたが、モデルの中に書くためのコードスニペットがありますが、私はネイティブソリューションに興味があります。

+0

このユースケース用に設計された[django-polymorphic](https://github.com/chrisglass/django_polymorphic)をご覧ください。モデルがforeignkeys、ManyToManyFieldsなどでフェッチされたときにも機能します。 – vdboor

+0

しないでください! :P私のテイクを下に見てください:http://stackoverflow.com/a/20353347/539490 – AJP

答えて

3

{{animal.sheep}}にアクセスすると成功するかもしれません。モデルの継承はあなたが考えるものではありません。そのような継承を暗黙のOneToOneField関係に "変換"する重いメタクラス機械があります。

+0

なぜ、この問題は正確かどうか、この回答を下降させたのか分かりません。しかし、少し不完全ですが、それでもなお正確です。 –

1

と呼ばれるとても簡単なdjangoアプリがあります。それは、あなた自身の "子"オブジェクトを返すモデル自体の上にdowncast()メソッドを提供するだけでなく、これらの問題に対処する特別なクエリーセットクラスを提供します!

ベースモデルのクエリーセットでselect_related()を使用すると、OneToOneFieldで参照される子オブジェクトも取得されることがあります。これは、ときどきパフォーマンスが向上することがあります。

8

は、執筆時点では、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' 
>>> 
+1

これは主にdjanogo-polymorphic-modelsの機能ですが、少し一般的な機能を提供しています.... –

+0

私はas_leaf_classメソッドが毎回dbにヒットすると思います。私がやったのは、selfを使ってクラスを直接設定することでした。class__ = model – Johan

+0

@johanはコードを変更しません。 2011年、Django pre 1.6では、 'get_query_set'が適切でした。訪問者に名前が変更されたことを知らせたい場合は、コメント内に追加してください。 –

0

あなたはこの答えを確認する必要があります:それは提案https://stackoverflow.com/a/929982/684253

ソリューションは、すでに@lazerscienceで言及されたジャンゴ・多形-モデルを、使用するのと同様です。しかし、私はdjango-model-utilsがdjango-polymorphicよりも少し良く書かれており、ライブラリは使いやすいと言っています。 「継承マネージャ」のreadmeを確認してください:https://github.com/carljm/django-model-utils/#readme

1

Djangoプロキシモデルの使用をお勧めします。あなたが使用する羊と馬によってサブクラス化されたベースモデル動物がある場合:

class Animal(models.Model): 
    pass 

class Horse(Animal): 
    class Meta(Animal.Meta): 
     proxy = True 

class Sheep(Animal): 
    class Meta(Animal.Meta): 
     proxy = True 

をこれがためwhat Proxy models are intendedはありませんが、あなたはモデル固有のデータを保存することの利点を必要としない限り、私は、Djangoの多型を使用してお勧めしません別々のテーブル。すべての馬固有の属性がデータベースに保存されているデフォルト値を持っていて、2つの馬オブジェクトしか持たないが100万匹の羊を持っている場合は、これについては、あなたが十分なディスク容量を持っていないと本当に関連しているに過ぎませんが、それはそうではありません。多型性がうまくいくとうまくいくが、そうでなければ痛みがある。

+0

親テーブル(つまり単一テーブル)の継承(希望の結合テーブル継承とは対照的に)を提案していますが、実際のモデルがその唯一の例かどうかは分かりません。 STIとJTIの間で学問的な議論があります。あなたは、JTIを開発するための効率的な方法について彼に助けなければなりません。 –