2012-04-12 74 views
1

我已經搜索了一段時間,但似乎無法找到這個問題的現有問題(雖然它可能是一個不知道術語的問題)。在Django中建模異構多對多關係的最佳方式是什麼?

我是Django的新手,並且一直在嘗試採用一種應該隨着時間的推移非常可擴展的設計,並使其與Django的ORM協同工作。實質上,它是一系列使用共享聯結表的多對多關係。

該設計是一個通用的遊戲製作系統,它說:「如果您滿足[需求],您可以使用[成本]作爲材料創建[獎勵]。」這樣可以使用同一個系統從任意數量的商店出售物品,並且通用性足以支持各種機械 - 我曾經見過它成功使用過。

Django不支持多個M2M關係共享相同結表(顯然是因爲它沒有辦法制定出反向關係),所以我似乎有下列選項:

  • 讓它打造自己的結點表,最終爲六個或更多,或者
  • 使用外鍵代替內置MTM關係的結點表。

第一個選項有點亂,因爲我知道我最終必須將其他字段添加到聯結表中。第二個選項工作得很好。不幸的是,因爲沒有從聯結表返回到其他每個表的外鍵,所以我經常與管理系統對抗,以便讓它按照我的意願去做。

下面是受影響的機型:

class Craft(models.Model): 
    name  = models.CharField(max_length=30) 
    description = models.CharField(max_length=300, blank=True) 
    cost  = models.ForeignKey('Container', related_name="craft_cost") 
    reward  = models.ForeignKey('Container', related_name="craft_reward") 
    require  = models.ForeignKey('Container', related_name="craft_require") 

class ShopContent(models.Model): 
    shopId  = models.ForeignKey(Shop) 
    cost  = models.ForeignKey('Container', related_name="shop_cost") 
    reward  = models.ForeignKey('Container', related_name="shop_reward") 
    require  = models.ForeignKey('Container', related_name="shop_require") 
    description = models.CharField(max_length=300) 

class Container(models.Model): 
    name  = models.CharField(max_length=30) 

class ContainerContent(models.Model): 
    containerId = models.ForeignKey(Container, verbose_name="Container") 
    itemId  = models.ForeignKey(Item, verbose_name="Item") 
    itemMin  = models.PositiveSmallIntegerField(verbose_name=u"min amount") 
    itemMax  = models.PositiveSmallIntegerField(verbose_name=u"max amount") 
    weight  = models.PositiveSmallIntegerField(null=True, blank=True) 
    optionGroup = models.PositiveSmallIntegerField(null=True, blank=True, 
                verbose_name=u"option group") 

有沒有更簡單,容易明顯的方式來得到這個工作?我試圖允許從Craft編輯界面上的每個相關列內聯編輯ContainerContent信息。

回答

3

這聽起來像你有一種「交易」,有一個名稱,描述和類型,並定義了成本,獎勵和要求。您應該將其定義爲單個模型,而不是多個模型(ShopContentCraft等)。

class Transaction(models.Model): 
    TYPE_CHOICES = (('Craft', 0), 
        ('Purchase', 1), 
        ) 
    name  = models.CharField(max_length=30) 
    description = models.CharField(max_length=300, blank=True) 
    cost  = models.ForeignKey('Container') 
    reward  = models.ForeignKey('Container') 
    require  = models.ForeignKey('Container') 
    type  = models.IntegerField(choices = TYPE_CHOICES) 

現在Shop等可以有一個ManyToManyFieldTransaction

無論是否使用這種特殊的模式,costrewardrequire關係都應該在同一個地方 - 如上述,或與CraftOneToOne關係,ShopContent等。你猜,你不應該有一大堆複雜的多對多的表都是真的一樣的。


您在您的文章底部提到,你

試圖允許的ContainerContent信息內聯編輯從Craft編輯界面上的每個相關列。

如果你建模關係的幾個層次,並使用管理應用程序,你需要或者應用某種nested inline補丁,或使用某種像我在我最近使用的聯繫方案的問題,How do I add a link from the Django admin page of one object to the admin page of a related object?

+0

鏈接的另一個版本:http://stackoverflow.com/questions/10115137/in-the-django-admin-is-there-a-way-to- show-a-list-of-actual-links-to-a-models – agf 2012-04-12 19:56:49

+0

嵌套內聯信息非常有用。我編輯了這個問題,以顯示關係問題稍好一些,但是多個表格將會經歷這個問題。不過,如果我最終這樣做,它會減少三分之一所需的桌子數量! – ThreeHams 2012-04-12 19:57:02

+0

@ThreeHams好的,如果你有多次相同的關係,你只需要建模一次。要麼像我的例子那樣推廣到單個模型,要麼使用顯式的'OneToOne'字段,或者使用帶有子類的隱式'OneToOne'字段。 – agf 2012-04-12 20:23:14

1

我是smelling這裏有些東西太複雜了,但我可能是錯的。作爲開始, 這是更好嗎? (ContainerContent稍後將想出)

class Cost(models.Model): 
    name  = models.CharField(max_length=30) 

class Reward(models.Model): 
    name  = models.CharField(max_length=30) 

class Require(models.Model): 
    name  = models.CharField(max_length=30) 

class Craft(models.Model): 
    name  = models.CharField(max_length=30) 
    description = models.CharField(max_length=300, blank=True) 
    cost  = models.ForeignKey(Cost) 
    reward  = models.ForeignKey(Reward) 
    require  = models.ForeignKey(Require) 

class Shop(models.Model): 
    name  = models.CharField(max_length=30) 
    crafts  = models.ManyToMany(Craft, blank=True) 
相關問題