1. ホーム
  2. python

[解決済み] django でオブジェクトの子クラスの名前を知らずにアクセスするにはどうしたらいいですか?

2023-06-23 08:47:17

質問

Django では、親クラスとそれを継承する複数の子クラスがある場合、通常は parentclass.childclass1_set や parentclass.childclass2_set を使って子にアクセスしますが、欲しい特定の子クラスの名前が分からない場合はどうすればいいでしょうか?

子クラス名を知らなくても、parent->child 方向に関連オブジェクトを取得する方法はありますか?

どのように解決するのですか?

( 更新 : Django 1.2 以降では、逆 OneToOneField 関係の select_related クエリに従うことができます (つまり、継承階層を下ることができます) が、より良い手法があります。 real_type フィールドを追加する必要がありません。これは 継承元 の中で django-model-utils プロジェクトに含まれています)。

これを行う通常の方法は、適切な "leaf" クラスのコンテントタイプを保存する親モデルの ContentType に ForeignKey を追加することです。 これを行わないと、継承ツリーの大きさによっては、インスタンスを見つけるために子テーブルで非常に多くのクエリーを実行しなければならないかもしれません。 以下は、私があるプロジェクトで行った方法です。

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

class InheritanceCastModel(models.Model):
    """
    An abstract base class that provides a ``real_type`` FK to ContentType.

    For use in trees of inherited models, to be able to downcast
    parent instances to their child types.

    """
    real_type = models.ForeignKey(ContentType, editable=False)

    def save(self, *args, **kwargs):
        if self._state.adding:
            self.real_type = self._get_real_type()
        super(InheritanceCastModel, self).save(*args, **kwargs)
    
    def _get_real_type(self):
        return ContentType.objects.get_for_model(type(self))
            
    def cast(self):
        return self.real_type.get_object_for_this_type(pk=self.pk)
    
    class Meta:
        abstract = True

これは再利用性を高めるために抽象的な基底クラスとして実装されています。これらのメソッドとFKを、特定の継承階層の親クラスに直接配置することも可能です。

この解決策は、親モデルを変更できない場合はうまくいきません。 その場合、すべてのサブクラスを手動でチェックすることになります。