web-dev-qa-db-ja.com

Django動的モデルフィールド

私はmulti-tenantedアプリケーションに取り組んでいます。このアプリケーションでは、一部のユーザーが(管理者を介して)自分のデータフィールドを定義して、フォームで追加データを収集し、データをレポートできます。後者のビットはJSONFieldを素晴らしい選択肢ではないので、代わりに次の解決策があります:

class CustomDataField(models.Model):
    """
    Abstract specification for arbitrary data fields.
    Not used for holding data itself, but metadata about the fields.
    """
    site = models.ForeignKey(Site, default=settings.SITE_ID)
    name = models.CharField(max_length=64)

    class Meta:
        abstract = True

class CustomDataValue(models.Model):
    """
    Abstract specification for arbitrary data.
    """
    value = models.CharField(max_length=1024)

    class Meta:
        abstract = True

CustomDataFieldがサイトへのForeignKeyを持っていることに注意してください。各サイトには異なるカスタムデータフィールドのセットがありますが、同じデータベースを使用します。次に、さまざまな具体的なデータフィールドを次のように定義できます。

class UserCustomDataField(CustomDataField):
    pass

class UserCustomDataValue(CustomDataValue):
    custom_field = models.ForeignKey(UserCustomDataField)
    user = models.ForeignKey(User, related_name='custom_data')

    class Meta:
        unique_together=(('user','custom_field'),)

これは、次の使用につながります。

custom_field = UserCustomDataField.objects.create(name='zodiac', site=my_site) #probably created in the admin
user = User.objects.create(username='foo')
user_sign = UserCustomDataValue(custom_field=custom_field, user=user, data='Libra')
user.custom_data.add(user_sign) #actually, what does this even do?

しかし、これは、特に関連データを手動で作成し、それを具体的なモデルに関連付ける必要があるため、非常に不格好です。より良いアプローチはありますか?

先制的に破棄されたオプション:

  • オンザフライでテーブルを変更するカスタムSQL。これは、これがスケーリングされないためと、ハッキングが多すぎるためです。
  • NoSQLのようなスキーマレスソリューション。私は彼らに対して何もしませんが、彼らはまだよく合いません。最終的にこのデータはisと入力され、サードパーティのレポートアプリケーションを使用する可能性があります。
  • 上記のJSONFieldは、クエリではうまく機能しないためです。
156
GDorn

Django-dynamoのアイデアをさらに推し進めています。プロジェクトはまだ文書化されていませんが、 https://github.com/charettes/Django-mutant でコードを読むことができます。

実際には、FKおよびM2Mフィールド(contrib.relatedを参照)も機能し、独自のカスタムフィールドのラッパーを定義することも可能です。

Unique_togetherやordering plus Model baseなどのモデルオプションもサポートされているため、モデルプロキシ、抽象、またはミックスインをサブクラス化できます。

実際には、メモリ内ではないロックメカニズムに取り組んで、古い定義を使用してモデル定義を複数のDjango実行インスタンス間で共有できるようにします。

このプロジェクトはまだ非常にアルファ版ですが、私のプロジェクトの基盤技術であるため、本番環境に持っていく必要があります。大きな計画ではDjango-nonrelもサポートしているため、mongodbドライバーを活用できます。

13
Simon Charette

さらなる調査により、これは エンティティ属性値 デザインパターンのやや特殊なケースであり、Djangoに対していくつかのパッケージによって実装されていることが明らかになりました。

まず、元の eav-Django プロジェクトがあります。これはPyPiにあります。

第二に、最初のプロジェクトのより最近のフォーク、 Django-eav があります。これは主に、Django自身のモデルまたはサードパーティアプリのモデルでEAVを使用できるようにするリファクタリングです。

4
GDorn