【问题标题】:Multiple M2M in djangodjango中的多个M2M
【发布时间】:2012-03-09 08:24:24
【问题描述】:

我在 Django 中有两个模型用于基于 2d 地图的游戏:

class Block(models.Model):
   type = models.IntegerField()

class ShopBuilding(models.Model):
   house_blocks = models.ManyToManyField(Block)
   street_blocks = models.ManyToManyField(Block)
   river_blocks = models.ManyToManyField(Block)
   decoration_blocks = models.ManyToManyField(Block)
   npc_blocks = models.ManyToManyField(Block)

现在我只想使用一张表关联这两个模型:

class ShopBlockAssoc(models.Model):
    block = models.ForeignKey(Block)
    shop = models.foreignKey(Shop)

ShopBuilding模型中设置through字段后,Django在syncdb时多次失败,比如

    Error: One or more models did not validate:
tnew.shopbuilding: Accessor for m2m field 'house_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'house_blocks'.
tnew.shopbuilding: Accessor for m2m field 'house_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'house_blocks'.
tnew.shopbuilding: Accessor for m2m field 'house_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'house_blocks'.
tnew.shopbuilding: Accessor for m2m field 'house_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'house_blocks'.
tnew.shopbuilding: Accessor for m2m field 'street_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'street_blocks'.
tnew.shopbuilding: Accessor for m2m field 'street_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'street_blocks'.
tnew.shopbuilding: Accessor for m2m field 'street_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'street_blocks'.
tnew.shopbuilding: Accessor for m2m field 'street_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'street_blocks'.
tnew.shopbuilding: Accessor for m2m field 'river_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'river_blocks'.
tnew.shopbuilding: Accessor for m2m field 'river_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'river_blocks'.
tnew.shopbuilding: Accessor for m2m field 'river_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'river_blocks'.
tnew.shopbuilding: Accessor for m2m field 'river_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'river_blocks'.
tnew.shopbuilding: Accessor for m2m field 'decoration_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'decoration_blocks'.
tnew.shopbuilding: Accessor for m2m field 'decoration_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'decoration_blocks'.
tnew.shopbuilding: Accessor for m2m field 'decoration_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'decoration_blocks'.
tnew.shopbuilding: Accessor for m2m field 'decoration_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'decoration_blocks'.
tnew.shopbuilding: Accessor for m2m field 'npc_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'npc_blocks'.
tnew.shopbuilding: Accessor for m2m field 'npc_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'npc_blocks'.
tnew.shopbuilding: Accessor for m2m field 'npc_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'npc_blocks'.
tnew.shopbuilding: Accessor for m2m field 'npc_blocks' clashes with related m2m field 'Block.shopbuilding_set'. Add a related_name argument to the definition for 'npc_blocks'.

如果我设置 db_table 字段 Django 会说:

The model has two manually-defined m2m relations through the model, which is not permitted. Please consider using an extra field on your intermediary model instead.

我该如何解决这个问题?我真的很想确保那些商店街区关系使用具有相同 db_table 的共享相同中间关联模型

【问题讨论】:

    标签: django model m2m


    【解决方案1】:

    问题是在模型Block 上它试图创建反向链接。 Django 根据模型命名这些链接,在您的情况下,对于所有 ManyToMany,它会尝试创建 shopbuilding_set 并且名称会发生​​冲突。为了避免这种情况,请添加related_name,例如:

    class ShopBuilding(models.Model):
       house_blocks = models.ManyToManyField(Block, related_name="shopbuilding_house_set")
       street_blocks = models.ManyToManyField(Block, related_name="shopbuilding_street_set")
       river_blocks = models.ManyToManyField(Block, related_name="shopbuilding_river_set")
       decoration_blocks = models.ManyToManyField(Block, related_name="shopbuilding_decoration_set")
       npc_blocks = models.ManyToManyField(Block, related_name="shopbuilding_npc_set")
    

    然后您就可以像这样从Block 实例访问ShopBuilding

    block.shopbuilding_npc_set.all()

    【讨论】:

    • 是的,谢谢,但是如何确保这些字段使用相同的中间模型?
    • 如果您想要一个中间模型,您不需要创建 5 个多对多关系,您只需创建一个。像 blocks = models.ManyToManyField(Block) 就是这样。问题是当你有一个中间模型时,你不能有“类型”
    • 所以基本上 Django ORM 不支持多个相同的 m2m 和一个 assoc 模型?
    • 您可以创建模型,添加“类型”字段并在通过中指定该模型。但是创建这样的对象更难,因为您总是必须指定“类型”字段等。Django 不会将许多多对多关系合并为一个。您始终可以创建一些“访问器”和管理器来帮助您处理自定义关系 (DRY)。
    • 无论如何,您指定的ShopBlockAssoc 模型是标准的多对多关系。基本上和写blocks = models.ManyToManyField(Block)是一样的。您可以从 ShopBuilding 中选择所有街区,也可以从街区中选择所有商店,但您没有房屋、街道、河流等类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    • 2013-02-05
    • 2013-06-25
    • 2019-04-15
    相关资源
    最近更新 更多