Django:为什么某些模型字段会相互冲突?


173

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

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

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

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

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

您能否解释为什么我会收到错误以及如何解决这些错误?


这些错误消息确实很好。他们已经解释了如何解决它们。并阅读** [ related_name文档中] **(docs.djangoproject.com/en/dev/ref/models/fields/#arguments)将解释它们为什么会发生。
Lutz Prechelt

Answers:


293

您有两个用户外键。Django自动创建一个从User到GameClaim的反向关系,通常是gameclaim_set。但是,由于您有两个FK,因此将具有两个gameclaim_set属性,这显然是不可能的。因此,您需要告诉Django用于反向关系的名称。

使用related_nameFK定义中的属性。例如

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

49
好的答案,但是我认为您在避免不礼貌方面没有成功:P除非您知道django在内部如何工作,否则“原因”并不明显。
肯尼2010年

14
对于刚学习框架的人来说,这并不明显。
jkyle 2011年

3
谢谢,错误消息对我也不是很明显,但是您对反向关系的解释非常有帮助。
ruquay 2011年

1
仅仅因为Clash是一支很好的乐队,并不能使他们成为特别具有描述性的错误信息;)
btown

7
还应该提到的是,如果不需要为所有模型使用反向关系。在某些情况下,您可能希望模型关系是一种方式。在这种情况下,请使用related_name ='+'。这告诉Django创建单向关系,而忽略反向关系。
汤米·斯特兰德

8

User模型试图创建具有相同名称的两个领域,一个是GameClaims说有User作为target,而另一个用于GameClaims该有User作为claimer。这是上的文档related_name,这是Django允许您设置属性名称的方法,以便自动生成的属性不会冲突。


7

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

从Django文档...

如果在ForeignKey或ManyToManyField上使用related_name属性,则必须始终为该字段指定唯一的反向名称。这通常会在抽象基类中引起问题,因为此类的字段包含在每个子类中,并且每次属性(包括related_name)的值都完全相同。

更多信息在这里


2

有时,您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

0

当我将子模块作为应用程序添加到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会导致所有数据库表都使用不正确的名称创建,因此这似乎是正确的方法。

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


0

只是添加约旦的答案(感谢约旦的提示),如果您在应用程序上方导入级别,然后导入应用程序,则也可能发生这种情况,例如

myproject/ apps/ foo_app/ bar_app/

因此,如果要导入应用程序foo_app和bar_app,则可能会遇到此问题。我的应用程序foo_app和bar_app都列在设置中。INSTALLED_APPS

而且您还是想避免导入应用程序,因为那样您会将相同的应用程序安装在2个不同的命名空间中

apps.foo_appfoo_app

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.