Django:为啥有些模型字段会相互冲突?
Posted
技术标签:
【中文标题】Django:为啥有些模型字段会相互冲突?【英文标题】:Django: Why do some model fields *** 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 参数。
您能否解释一下我收到错误的原因以及如何解决这些错误?
【问题讨论】:
这些错误信息非常好。他们已经解释了如何修复它们。阅读 **[related_name
in the documentation]**(docs.djangoproject.com/en/dev/ref/models/fields/#arguments) 将解释它们发生的原因。
【参考方案1】:
User
模型正在尝试创建两个具有相同名称的字段,一个用于具有 User
作为 target
的 GameClaims
,另一个用于具有 User
的 GameClaims
作为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 内部是如何工作的,否则“为什么”并不明显。 对于刚刚学习框架的人来说,这并不明显。 谢谢,错误信息对我来说也不是很明显,但是您对反向关系的解释非常有帮助。 仅仅因为 *** 是一支优秀的乐队,并不能使它们成为特别具有描述性的错误消息;) 还应该提到,如果您不需要对所有模型使用反向关系。在某些情况下,您可能希望模型关系是一种方式。在这种情况下,您使用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_app
和
foo_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
【讨论】:
以上是关于Django:为啥有些模型字段会相互冲突?的主要内容,如果未能解决你的问题,请参考以下文章