0

私は現在、Django を使用して何かをモデル化する方法について冗談を言っています。chassis基本的な状況は、 として機能し、いくつかの を提供するオブジェクトがあるということsocketsです。次に、のmodulesに配置されるさまざまな負荷があります。これらの異なるものを Django の個別のクラスとしてモデル化したいと思いますが、データベース層で共通のクラスを使用し、おそらくいくつかの汎用フィールドを使用します。socketschassismodules

したがって、データベース モデルは次のようになります。

class Module(models.model):
    name = models.CharField(max_length=128)
    # Or is there a better way to annotate a type?
    type = models.CharField(max_length=128) 
    string1 = models.CharField(max_length=128)
    string2 = models.CharField(max_length=128)
    ...
    int1 = models.IntegerField()

# Some kind of engine class that derives from Module
# but does nothing else then "mapping" the generic
# fields to something sensible

class Socket(models.Model):
    is_on = models.ForeignKey(Chassis)
    name = models.CharField(max_length=128)
    type = models.CharField(max_length=128)

class Connection(models.Model):
    chassis = models.ForeignKey(Chassis)
    module = models.ForeignKey(Module)
    via = models.ForeignKey(Socket)

class Chassis(models.Model):
    name = models.CharField(max_length=128)
    modules= models.ManyToManyField(Module, through='Connection')

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

もちろん、この非正規化で論理を台無しにしたくはありません。engineそのため、Module テーブルを使用する必要があるが、「Horsepower」などのデータを「int1」に効果的にマッピングする「論理」ゲッターとセッターを提供するある種のクラスを示唆しました。

したがって、私の質問は基本的に次のとおりです。

  • 私がDjangoでやっていることは合理的ですか? または、これに対処するためのより良い(おそらく組み込みの)方法はありますか?
  • フィールドに応じて、非正規化モデルのラッパーメソッドを提供する正しいタイプをModule.type自動的に構築することは可能でしょうか?
4

2 に答える 2

1

私がDjangoでやっていることは合理的ですか?

一般的な考え方は問題ありませんが、非正規化によってクエリが最適でなくなる可能性があります。Module標準的な解決策は、モジュールの種類ごとにサブクラス化することです。これにより、moduleテーブルに加えて、タイプ固有のものを含むモジュールタイプごとのテーブルが作成されます。もちろん、これは、実行時にモジュール タイプを作成または削除しないことを前提としています。

とはいえ、モデルにはいくつかの問題があります。

class Module(models.model):
    name = models.CharField(max_length=128)
    # Or is there a better way to annotate a type?
    type = models.CharField(max_length=128) 
    string1 = models.CharField(max_length=128)
    string2 = models.CharField(max_length=128)
    ...
    int1 = models.IntegerField()

通常、typeスペースを節約するために正規化されます。

class ModuleType(models.model):
    name = models.CharField(max_length=128)
    # Any other type-specific parameters.

class Module(models.model):
    name = models.CharField(max_length=128)
    type = models.ForeignKey(ModuleType, related_name="modules")
    string1 = models.CharField(max_length=128)
    string2 = models.CharField(max_length=128)
    ...
    int1 = models.IntegerField()

class Socket(models.Model):
    is_on = models.ForeignKey(Chassis)
    name = models.CharField(max_length=128)
    type = models.CharField(max_length=128)

class Connection(models.Model):
    chassis = models.ForeignKey(Chassis)
    module = models.ForeignKey(Module)
    via = models.ForeignKey(Socket)

class Chassis(models.Model):
    name = models.CharField(max_length=128)
    sockets = m
    modules= models.ManyToManyField(Model, through='Socket')

Chassis混乱です。を定義せず、おそらく必要な場所socketsに書き、おそらく参照する必要があります(モデルにはリンクの両端に s が必要です)。しかし、あなたの説明から、私ははるかに簡単になります:ModelmodulethroughConnectionthroughForeignKey

class Socket(models.Model):
    chassis = models.ForeignKey(Chassis, related_name="sockets")
    name = models.CharField(max_length=128)
    # Is `type` a ModuleType? If so, use a ForeignKey.
    # If not, create a SocketType model.
    type = models.___
    module = models.ForeignKey(Module, related_name="sockets")

class Chassis(models.Model):
    name = models.CharField(max_length=128)
    sockets = models.IntegerField()
    modules = models.ManyToManyField(Socket)

何をモデリングしているかをよりよく説明することで、これをさらに洗練させることができます。たとえば、ManyToMany があなたの望むものかどうかはわかりません。シャーシの設計(ソケットを含む特定の種類のシャーシのすべてのインスタンスに共通するもの) をそのシャーシのインスタンス(設計を参照し、ソケットをモジュールにマッピングする別のテーブルを持つ) から分割する必要がある場合があります。 .


Module.type フィールドに応じて、正しい型を自動的に構築することは可能でしょうか?

それがファクトリーデザインパターンです。Python では、コンストラクターの辞書として実装します。

class Module(models.model):
    # ...
    CONSTRUCTORS = {}

    @staticmethod
    def register_constructor(type_name, constructor):
        Module.CONSTRUCTORS[type_name] = constructor

    def construct(self):
        return Module.CONSTRUCTORS[self.type.name](self)

特定のエンジン クラスは必要ないと思います。さまざまなモジュール クラスで十分です。

于 2012-09-19T13:13:58.170 に答える
1

抽象基本クラスを定義するには、次のようにします。

class Module(models.model):
    name = models.CharField(max_length=128)
    type = models.CharField(max_length=128) 
    string1 = models.CharField(max_length=128)
    string2 = models.CharField(max_length=128)
    ...
    int1 = models.IntegerField()

    class Meta:
        abstract = True

class SpecificModule(Module):
     subClassField = models.CharField(max_length=128)

ドキュメントのこの部分を読むことをお勧めします。これは、継承と抽象クラスを扱うための完全に良い出発点です。

なしで親 Module クラスを定義することもできますclass Meta: abstract = True。唯一の違いはabstract = True、クラスSpecificModuleのすべてのフィールドと抽象モジュールの親クラスのすべてのフィールドが、クラス SpecificModule のサブクラス テーブルに作成されるのに対し、abstract = True定義がない場合、クラス Module のテーブルが作成され、すべてが " Module テーブルで使用可能な「ジェネリック」フィールド、およびクラス SpecificModule のテーブル内のすべてのサブクラス固有フィールド。

編集:親子関係に関する質問への回答。

サブクラス テーブル ( docs ) に暗黙的な 1 対 1 フィールドが作成されるため、このクエリを使用して子オブジェクトを取得できます。

#get the parent
parent = Module.objects.get(name="my first module")
#this is possible
print parent.name
>>> "my first module"
#this is not possible
print parent.subClassField
>>> Traceback (most recent call last):
    File "<console>", line 1, in <module>
    AttributeError: 'Module' object has no attribute 'subClassField'
#get the corresponding child
child = SpecificModule.objects.get(module_ptr_id=parent.pk)
#finally we can print the value
print child.subClassField

Django によって作成されるデフォルトの related_name も必要だと思いますが、それがどれであるかはわかりません。

親から子への暗黙の 1 対 1 の関係は、このabstract=False場合にのみ作成されることに注意してください。それにもかかわらずabstract = True、抽象的であるため、抽象的な親をオブジェクトとして使用できない場合..

于 2012-09-19T13:15:07.720 に答える