2

私の望みは、共通のロケーション モデルを作成し、ロケーションを必要とするさまざまな上位レベルのモデルがそれを参照できるようにすることです。

管理者に複数の部分からなるフォーム (インライン) を表示して、発行元と建物の上位レベルの情報と、それぞれの位置情報を入力できるようにしたいと考えています。インライン システムは、このように動作することを望まないようです。

明らかに、これは非常に標準的な種類の問題のように思えるので、私は何か非常に間違ったことをしています。私のスキーマ設計は失敗していますか?

私は愚かにインラインシステムを使用していますか? 上位レベルのオブジェクトごとに Location のサブクラスを作成したくありません。これは、上位レベルのオブジェクト (メーリング リストや地理的なルックアップなど) に関係なく、さまざまな方法で場所を操作したいからです。

models.py:
...
class Location(models.Model):
    """
    A geographical address
    """
# Standard Location stuff   
    address_line1 = models.CharField("Address line 1", max_length = 45, null=True, blank=True)
    ...

class Publisher(models.Model):
    """
    Contains Publisher information for publishers of yearbooks.  Replaces Institution from 1.x
    """
    name =  models.CharField(max_length=100, null=False, help_text="Name of publisher, e.g. University of Kansas")
    groups = models.ManyToManyField(Group, help_text="Select groups that this publisher owns.  Usually just one, but multiple groups are possible.")
    is_active = models.BooleanField(help_text="Check this box to enable this publisher.")
    location = models.OneToOneField(Location)
    ...

class Building(models.Model):
    """
    Contains Building Information
    """
    name =  models.CharField(max_length=100, null=False, help_text="Name of building, e.g. Physical Sciences")
    is_active = models.BooleanField(help_text="Check this box to enable this building.")
    location = models.OneToOneField(Location)
    ...

admin.py:
...
class LocationInline(generic.GenericStackedInline):
    model = Location
    max_num = 1
    extra = 1

class PublisherAdmin(admin.ModelAdmin):
    model = Publisher
    inlines = [ LocationInline,
    ]

class BuildingAdmin(admin.ModelAdmin):
    model = Building
    inlines = [ LocationInline,
    ]

admin.site.register(Publisher, PublisherAdmin)
admin.site.register(Building, BuildingAdmin)

これを Location モデルに追加することで、インラインの読み込みと表示を強制できます。

# Support reverse lookup for admin  
    object_id    = models.PositiveIntegerField()
    content_type = models.ForeignKey(ContentType)
    of           = generic.GenericForeignKey('content_type', 'object_id' )

しかし、これを行うと、インライン オブジェクトを取得して編集することはできますが、Location がそれを作成したオブジェクトの ID を格納しているため、関係が逆になっているように見えます。

すべてがうまく機能するようにするための推奨されるスキーマ変更 (Django は非常に優れているため) や、後ろ向きに見えるものを意味のあるものにするためのトリックなど、どんな助けも大歓迎です。

4

2 に答える 2

1

ドメインモデルに関して言えば、それを行うための「1つの正しい方法」のようなものはありません。それは、特定のアプリケーションの要件によって異なります。

wrt /あなたの問題:

OneToOneフィールドは、モデルをモデルインスタンスごとに1つのロケーションに制限します。これは(Gregが述べたように)、ロケーションのフィールドをモデルに直接貼り付けることと概念的にはそれほど違いはありません。wrt / DRY / factorisation / reuseなど、モデルの継承を使用してこれを実行することもできます。抽象(またはアプリにとって意味がある場合は最終的には具体的な)ロケーションモデルを使用します。

ForeignKeyソリューションは、PublisherモデルとBuildingモデルを単一の場所に制限しますが(希望する場所である場合とそうでない場合があります)、特定の場所が異なるPublisherやBuildingインスタンス間で共有される場合があります。これは、特定の場所を1つ編集すると、関連するすべてのインスタンスが反映されることを意味します(ここでは不要な副作用に注意してください)。

LocationモデルでGenericForeignKeyを使用するということは、特定のロケーションインスタンスが唯一の関連オブジェクトに属することを意味します。上記のソリューションのような驚くべき副作用はありませんが、同じ値の場所が重複している可能性があり(つまり、建物用に1つ、発行元用に1つ)、特定の場所(または少なくとも簡単ではありません)。また、これにより、PublisherまたはBuildingインスタンスに複数の場所が存在することを防ぐことはできませんが、これも問題ない場合があります。wrt / Locationインスタンスは、それらが属するオブジェクトの「IDを保存」します。これが、この設計上の選択が実際に意味することです。Locationは、他のオブジェクト、期間に「属します」。

いずれにせよ、Djangoの管理アプリのデフォルトの動作を中心に設計することはおそらく最も賢明なことではありません。最初に、このアプリケーションにとって何が理にかなっているのかを判断する必要があります(また、パブリッシャーとビルディングのニーズが異なる場合があります)。次に、ニーズに合わせて管理者を拡張する必要があります。

于 2012-06-30T10:47:57.630 に答える
1

まず、OneToOneField ではなく、ForeignKey が必要だと思います。それ以外の場合は、ロケーション フィールドを Publisher モデルと Building モデルに追加するだけで済みます。次に、場所を選択するためのドロップダウンと、必要に応じて建物と発行者の管理で新しい場所を追加するためのリンクを取得します。

建物/パブリッシャーごとに 1 つのロケーション インスタンスが本当に必要な場合は、一般的な外部キーを追加しない限り、インライン モデルには親モデルを指す ForeignKey が必要なため、インラインとして編集することはできません。これは「後方」ではありません。タイプに関係なく、オブジェクトを他のオブジェクトにアタッチできるようにする場合に有効なオプションです。

于 2012-06-30T06:31:07.837 に答える