2012-04-12 66 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) 
相关问题