Django models.py 循环外键

Posted

技术标签:

【中文标题】Django models.py 循环外键【英文标题】:Django models.py Circular Foreign Key 【发布时间】:2011-04-10 14:20:24 【问题描述】:

我有一个 django 应用程序,它基本上只是一个相册。现在我有两个模型:ImageAlbum。除其他外,每个Album 都有一个指向Image 的外键作为其缩略图,每个Image 都有一个指向它所属的Album 的外键。但是,当我尝试使用manage.py syncdbmanage.py sqlall 我收到错误消息,提示未在 models.py 中首先定义的类在定义的第一个类中使用时未定义。

models.py(删节):

from django.db import models
import os

class Album(models.Model):
    thumb = models.ForeignKey(Image, null=True, blank=True)

class Image(models.Model):
    image = models.ImageField(upload_to='t_pics/images')
    thumb = models.ImageField(upload_to='t_pics/images/thumbs')
    album = models.ForeignKey(Album)

当我执行manage.py sqlall appname 时出现错误:

[...]
 File "/path/to/file/appname/models.py", line 4, in ?
    class Album(models.Model):
  File "/path/to/file/appname/models.py", line 5, in Album
    thumb = models.ForeignKey(Image, null=True, blank=True)
NameError: name 'Image' is not defined

当我在 models.py 中切换类的顺序时,我得到了同样的错误,除了它说 'Album' undefined 而不是 'Image' undefined 我还尝试在第一个类中注释依赖关系,然后在其他所有内容成功导入后取消注释,但是那没有帮助。我应该如何去做这项工作?我不愿意做一个完整的第三类Thumb,因为它会有很多与Image相同的代码我也很确定我可以手动将外键添加到数据库中,但我希望它是干净的而不是 hackish。

【问题讨论】:

【参考方案1】:

您实际上没有循环引用;问题是,在您定义专辑时,您还没有定义图像。你可以改用字符串来解决这个问题:

class Album(models.model):
  thumb = models.ForeignKey('Image', null=True, blank=True)

但是,在这种情况下,您可能希望使用 OneToOneField 而不是外键。 (请注意,您仍然必须对字符串使用该技巧)。

【讨论】:

您的解决方案有效,但我还必须将 related_name='Image' 添加到 Album.thumb 定义的参数中。 OneToOneField 比 ForeignKey 有什么优势? OneToOneField 对外键实施唯一限制。此外,您只需在其中一个类上设置它,而另一个“免费”获得反向链接。 顺便说一句,反向链接也可以免费使用 ForeignKey,但它返回一个查询集而不是单个项目【参考方案2】:

使用引号强制惰性引用:

models.ForeignKey('Image', null=True, blank=True)

此外,ForeignKey.related_name 是您的朋友(避免反向引用名称冲突)。

【讨论】:

@puddingfox 你知道你可以改变选择的正确答案吗? @Kevin:我猜你熟悉像 javascript 这样的柯里化语言,但是在 Python 中,你必须在引用之前声明一个变量(这个“make-it-a-string”技巧是处理这个事实的 Django 约定)。变量柯里化也可能令人困惑——如果你有时间深入研究 Python 命名空间,它是我最喜欢的 Python 语言特征之一。【参考方案3】:

这是旧的,但无论如何,我想说我没有看到模型图像中属性专辑的原因。在我看来,它并不是真正需要的。

【讨论】:

我不同意你的观点——尽管现在已经过了一段时间了。他希望他的数据库允许这张专辑只有一个可能的缩略图。表达这一点最自然的方式是让图像用 FK 引用专辑,而专辑用 FK 引用单个图像。通过在专辑上有一个 FK,您会自动强制只有一个。我能想到的唯一替代方法是建模需要一些相对更复杂的约束或应用程序代码本身的额外逻辑来保证这一点。

以上是关于Django models.py 循环外键的主要内容,如果未能解决你的问题,请参考以下文章

具有默认值的外键上的 Django 1.7 迁移错误

models.py中增加了字段,django中怎样更新

如何在 django rest 中自动继承外键模型的字段?

Django 模型 - 外键作为主键

Django REST Framework 中的外键值

Django - 如何为模型的外键制作表单?