在 Django 中建模异构多对多关系的最佳方法是啥?
Posted
技术标签:
【中文标题】在 Django 中建模异构多对多关系的最佳方法是啥?【英文标题】:What is the best way to model a heterogenous many-to-many relationship in Django?在 Django 中建模异构多对多关系的最佳方法是什么? 【发布时间】:2012-04-25 04:17:39 【问题描述】:我已经搜索了一段时间,但似乎找不到与此相关的现有问题(尽管可能是不知道术语的问题)。
我是 Django 新手,并且一直在尝试采用随着时间的推移应该非常可扩展的设计,并使其与 Django 的 ORM 一起使用。本质上,它是一系列使用共享联结表的多对多关系。
设计是一个通用的游戏制作系统,上面写着“如果你满足[要求],你可以使用[成本]作为材料来创造[奖励]。”这允许使用相同系统从任意数量的商店出售物品,并且通用性足以支持广泛的机制 - 我在过去看到它成功使用过。
Django 不支持共享同一个联结表的多个 M2M 关系(显然是因为它无法计算出反向关系),所以我似乎有这些选择:
让它创建自己的联结表,最终有六个或更多,或者 使用联结表的外键代替内置的 MTM 关系。第一个选项有点混乱,因为我知道我最终必须在联结表中添加额外的字段。第二个选项效果很好。不幸的是,由于没有从联结表 BACK 到其他每个表的外键,我一直在与管理系统作斗争,以让它做我想做的事。
以下是受影响的型号:
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 信息进行内联编辑。
【问题讨论】:
【参考方案1】:听起来您有一种“交易”,它具有名称、描述和类型,并定义了成本、奖励和要求。您应该将其定义为单个模型,而不是多个模型(ShopContent
、Craft
等)。
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
等可以有一个ManyToManyField
到Transaction
。
无论您是否使用此特定模型,cost
、reward
和 require
关系都应该在一个地方 -- 如上所述,或者在 OneToOne
与 Craft
、ShopContent
的关系中等等。正如你所猜想的,你不应该有一大堆复杂的多对多 through
表,它们都完全相同。
您在帖子底部提到您是
尝试允许在
Craft
编辑界面上的每个相关列中对ContainerContent
信息进行内联编辑。
如果您要对多个级别的关系进行建模,并使用管理应用程序,则需要应用某种 nested inline 补丁,或使用某种链接方案,例如我在最近的问题中使用的那种, How do I add a link from the Django admin page of one object to the admin page of a related object?
【讨论】:
另一个版本的链接:***.com/questions/10115137/… 嵌套的内联信息真的很有用。不过,我编辑了问题以更好地显示关系问题 - 多个表将通过这个表。不过,如果我最终这样做,它会减少三分之一所需的桌子数量! @ThreeHams 好的,如果你有多次相同的关系,你只需要建模一次。要么像我的示例那样泛化为单个模型,要么使用显式OneToOne
字段,或使用带有子类化的隐式 OneToOne
字段。
事务更改实际上效果很好。希望它能够经受住未来的变化,但它从设计中删除了两个表和三个复杂的关系。谢谢您的帮助!就内联编辑而言,我已经意识到我计划的 CMS 的范围远远超出了内置管理界面。考虑到我不断遇到的限制,最好使用现有的作为指导,从头开始构建我的。【参考方案2】:
我是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)
【讨论】:
以上是关于在 Django 中建模异构多对多关系的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章