【问题标题】:Django: Why do some model fields clash with each other?Django:为什么有些模型字段会相互冲突?
【发布时间】:2010-11-11 15:48:56
【问题描述】:

我想创建一个包含 2 个指向用户的链接的对象。例如:

class GameClaim(models.Model):
    target = models.ForeignKey(User)
    claimer = models.ForeignKey(User)
    isAccepted = models.BooleanField()

但在运行服务器时出现以下错误:

  • 字段“target”的访问器与相关字段“User.gameclaim_set”发生冲突。在“target”的定义中添加一个related_name 参数。

  • 字段“claimer”的访问器与相关字段“User.gameclaim_set”发生冲突。为 'claimer' 的定义添加一个 related_name 参数。

您能否解释一下我收到错误的原因以及如何解决这些错误?

【问题讨论】:

标签: python django django-models


【解决方案1】:

User 模型正在尝试创建两个具有相同名称的字段,一个用于具有 User 作为 targetGameClaims,另一个用于具有 UserGameClaims作为claimer。这是docs on related_name,这是 Django 让您设置属性名称的方式,因此自动生成的属性不会冲突。

【讨论】:

    【解决方案2】:

    您有两个 User 的外键。 Django 自动创建从 User 到 GameClaim 的反向关系,通常为gameclaim_set。但是,因为您有两个 FK,所以您将有两个 gameclaim_set 属性,这显然是不可能的。所以你需要告诉 Django 为反向关系使用什么名字。

    在 FK 定义中使用 related_name 属性。例如

    class GameClaim(models.Model):
        target = models.ForeignKey(User, related_name='gameclaim_targets')
        claimer = models.ForeignKey(User, related_name='gameclaim_users')
        isAccepted = models.BooleanField()
    

    【讨论】:

    • 很好的答案,但我不认为你成功地避免了粗鲁:P 除非你知道 django 内部是如何工作的,否则“为什么”并不明显。
    • 对于刚刚学习框架的人来说,这并不明显。
    • 谢谢,错误信息对我来说也不是很明显,但是您对反向关系的解释非常有帮助。
    • 仅仅因为 Clash 是一支优秀的乐队,并不能使它们成为特别具有描述性的错误消息;)
    • 还应该提到,如果您不需要对所有模型使用反向关系。在某些情况下,您可能希望模型关系是一种方式。在这种情况下,您使用related_name='+'。这告诉 Django 创建单向关系并忽略反向关系。
    【解决方案3】:

    OP 没有使用抽象基类...但如果您使用了,您会发现硬编码 FK 中的 related_name(例如 ...,related_name="myname")会导致许多这些冲突错误 - 每个从基类继承的类都有一个。下面提供的链接包含解决方法,它很简单,但绝对不明显。

    来自 django 文档...

    如果您使用的是related_name ForeignKey 上的属性或 ManyToManyField,你必须总是 指定一个唯一的反向名称 场地。这通常会导致 抽象基类中的问题, 因为这个类的字段是 包含在每个孩子中 类,具有完全相同的值 对于属性(包括 相关名称)。

    更多信息here.

    【讨论】:

      【解决方案4】:

      当我将子模块作为应用程序添加到 django 项目时,我似乎偶尔会遇到这种情况,例如给定以下结构:

      myapp/
      myapp/module/
      myapp/module/models.py
      

      如果我将以下内容添加到 INSTALLED_APPS:

      'myapp',
      'myapp.module',
      

      Django 似乎两次处理 myapp.mymodule models.py 文件并抛出上述错误。这可以通过在 INSTALLED_APPS 列表中不包括主模块来解决:

      'myapp.module',
      

      包含myapp 而不是myapp.module 会导致创建的所有数据库表名称不正确,因此这似乎是正确的方法。

      我在寻找这个问题的解决方案时遇到了这篇文章,所以我想把它放在这里:)

      【讨论】:

        【解决方案5】:

        只是添加到乔丹的答案(感谢乔丹的提示),如果您导入应用程序上方的级别然后导入应用程序,例如

        myproject/ apps/ foo_app/ bar_app/

        因此,如果您正在导入应用程序 foo_app 和 bar_app ,那么您可能会遇到这个问题。我的应用程序 foo_app 和 bar_app 都列在 settings.INSTALLED_APPS

        并且无论如何您都希望避免导入应用程序,因为这样您就在 2 个不同的命名空间中安装了同一个应用程序

        apps.foo_appfoo_app

        【讨论】:

          【解决方案6】:

          有时您必须在related_name 中使用额外的格式 - 实际上,任何时候使用继承。

          class Value(models.Model):
              value = models.DecimalField(decimal_places=2, max_digits=5)
              animal = models.ForeignKey(
                  Animal, related_name="%(app_label)s_%(class)s_related")
          
              class Meta:
                  abstract = True
          
          class Height(Value):
              pass
          
          class Weigth(Value):
              pass
          
          class Length(Value):
              pass
          

          这里没有冲突,但是related_name 定义一次,Django 将负责创建唯一的关系名称。

          然后在 Value 类的孩子中,您将可以访问:

          herdboard_height_related
          herdboard_lenght_related
          herdboard_weight_related
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-11-09
            • 2022-10-24
            • 2011-02-21
            • 1970-01-01
            • 2021-01-09
            • 2014-12-22
            • 1970-01-01
            相关资源
            最近更新 更多