13

モデル継承を使用する場合、django-model オブジェクトの実際のクラスを見つけようとしています。

問題を説明するコード:

class Base(models.model):
    def basemethod(self):
        ...

class Child_1(Base):
    pass

class Child_2(Base):
    pass

2 つの Child クラスのさまざまなオブジェクトを作成し、それらすべてを含むクエリセットを作成すると、次のようになります。

Child_1().save()
Child_2().save()
(o1, o2) = Base.objects.all()

オブジェクトが basemethod で Child_1 または Child_2 のどちらのタイプであるかを判断したいのですが、o1.child_1 および o2.child_2 を介して子オブジェクトにアクセスできますが、それは基本クラスの子クラスに関する知識を再征服します。

私は次のコードを思いつきました:

def concrete_instance(self):
    instance = None
    for subclass in self._meta.get_all_related_objects():
        acc_name = subclass.get_accessor_name()
        try:
            instance = self.__getattribute__(acc_name)
            return instance
        except Exception, e:
            pass

しかし、それはもろく感じられ、さらに多くのレベルで継承するとどうなるかわかりません.

4

5 に答える 5

14

Django は、親モデルのテーブルと子モデルのテーブルの間に OneToOneField を使用してモデルの継承を実装します。するとBase.object.all()、Django はベース テーブルのみを照会するため、子テーブルが何であるかを知る方法がありません。したがって、残念ながら、追加のクエリなしで子モデル インスタンスに直接移動することはできません。

このスニペットは、基本モデルに ContentType フィールドを追加する一般的な方法を示しています。

from django.contrib.contenttypes.models import ContentType

class Base(models.Model):
    content_type = models.ForeignKey(ContentType,editable=False,null=True)

    def save(self):
        if(not self.content_type):
            self.content_type = ContentType.objects.get_for_model(self.__class__)
        self.save_base()

    def as_leaf_class(self):
        content_type = self.content_type
        model = content_type.model_class()
        if(model == Base):
            return self
        return model.objects.get(id=self.id)

if Base.content_type.model_class()次に、タイプを決定すると言うことができます。

カスタム マネージャーをミックスに追加する別のスニペットを次に示します。

ご覧のとおり、これらのソリューションはどちらも非常に高価になる可能性があります。多数のインスタンスがある場合、as_leaf_class() メソッドを使用すると、アイテムごとに 1 つのクエリが必要になります。

代わりに、既知の子モデルのセットがある場合は、各モデルを個別にクエリして、インスタンスを 1 つのリストに集約します。

于 2008-12-08T13:05:59.620 に答える
5

django-model-utils のInheritanceManager を見てください。これをモデルにアタッチすると、(少なくとも最初のレベルでは) 具体的な子クラスが得られます。

from model_utils.managers import InheritanceManager

class Base(models.Model):
    objects = InheritanceManager()

# ...

Base.objects.all().select_subclasses() # returns instances of child classes

model-utils には Django 1.2 以降が必要です。

于 2011-12-12T17:59:21.447 に答える
0

Daniel Naab が提案したもののわずかに修正されたバージョン:

from django.contrib.contenttypes.models import ContentType
from django.db import models

def ParentClass(models.Model):
    superclass = models.CharField(max_length = 255, blank = True)

    def save(self, *args, **kwargs):
        if not self.superclass:
            self.superclass = ContentType.objects.get_for_model(self.__class__)

        super(ParentClass, self).save(*args, **kwargs)

    def getChild(self):
        s = getattr(self, self.superclass)
        if hasattr(s, 'pk'):
            return s
        else:
            return None

class Child1(ParentClass):
    pass

class Child2(ParentClass):
    pass
于 2013-07-03T08:56:44.473 に答える
0

うーん...私の問題は。ビューでは、この主要なモデルがあり、「Big_Model」としましょう。「Big_Model」に関連する「Small_Model」がいくつかありました。したがって、「Big_Model」の特定のインスタンスに関連するすべての「Small_Model」を取得したい場合は、**_set.all() を実行しました。しかし要点は、Small_Model には子クラスがあり、views.py で、関連する Small_Model インスタンスのそれぞれがどの子クラスであるかを取得したかったということです。私のトリックは、モデル Small_Model で is_child_1() や is_child_2() のようなブール型メソッドを定義することでした。true の場合は、Small_Model ポインターの代わりに実際の子ポインターを適用します。

わかりました...十分に明確ではありませんが、良い例を書く時間がないので、ここに私のケースをコピーして貼り付けます:

class Cache(models.Model):
  valor = models.DecimalField(max_digits=9, decimal_places=2, blank= True, null= True)
  evento=models.ForeignKey(Evento)
  def __unicode__(self):
    return u'%s: %s' % (self.evento, self.valor)
  class Meta:
    verbose_name='Cachê'
    verbose_name_plural='Cachês'
  def is_cb(self):
    try:
      self.cache_bilheteria
      return True
    except self.DoesNotExist:
      return False
  def is_co(self):
    try:
      self.cache_outro
      return True
    except self.DoesNotExist:
      return False
于 2010-05-29T19:19:48.387 に答える
-2

あるので脆く感じます。(これは、別のコンテキストでの回答の転載です。 プログラムによる C++ のキャストを参照してください。実行できますか? )

ポリモーフィズムについて読んでください。ほとんどすべての「動的キャスト」の状況は、ポリモーフィズムの実装に苦労している例です。

動的キャストで行う決定は、すでに行われています。実際の作業をサブクラスに委任するだけです。

例の最も重要な部分を省略しました。便利で多様な作品。

「オブジェクトのタイプが Child_1 か Child_2 かを判断したい...」と言ったとき、「aMethod()各サブクラスに固有の方法でオブジェクトを実行できるようにするため」を省略しました。そのメソッドは有用な作業であり、単純に両方のサブクラスのメソッドである必要があります。

class Base(models.model):
    def aMethod(self):
        # base class implementation.

class Child_1(Base):
    def aMethod(self):
        # Child_1 override of base class behavior.

class Child_2(Base):
    def aMethod(self):
        supert( Child_2, self ).aMethod() # Invoke the base class version
        # Child_2 extension to base class behavior.

同じメソッド、複数の実装。「実行時の型識別」や具体的なクラスの決定は必要ありません。

于 2008-12-08T11:23:59.090 に答える