Django - 循环模型导入问题

175

我真的不理解这个,如果有人能够解释一下这是怎么工作的,我会非常感激。我有两个应用程序,一个是“账户(Accounts)”,另一个是“主题(Theme)”......以下是我的设置列表:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'accounts',
    'themes',
)

在账户中,我正在尝试做这件事:

from themes.models import Theme

class Account(models.Model):
    ACTIVE_STATUS = 1
    DEACTIVE_STATUS = 2
    ARCHIVE_STATUS = 3
    STATUS_CHOICES = (
        (ACTIVE_STATUS, ('Active')),
        (DEACTIVE_STATUS, ('Deactive')),
        (ARCHIVE_STATUS, ('Archived')),
    )

    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=250)
    slug = models.SlugField(unique=True, verbose_name='URL Slug')
    status = models.IntegerField(choices=STATUS_CHOICES, default=ACTIVE_STATUS, max_length=1)
    owner = models.ForeignKey(User)
    enable_comments = models.BooleanField(default=True)
    theme = models.ForeignKey(Theme)
    date_created = models.DateTimeField(default=datetime.now)

在我的主题模型中:

class Theme(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=250)
    slug = models.SlugField(unique=True, verbose_name='URL Slug')
    date_created = models.DateTimeField(default=datetime.now)

class Stylesheet(models.Model):
    id = models.AutoField(primary_key=True)
    account = models.ForeignKey(Account)
    date_created = models.DateTimeField(default=datetime.now)
    content = models.TextField()

Django 抛出了以下错误:

from themes.models import Theme
ImportError: cannot import name Theme

这是某种循环导入问题吗?我尝试使用延迟引用,但似乎也不起作用!


1
看起来似乎是循环导入的问题。为什么您需要从定义 Theme 的模块中导入 Account - Dominic Rodger
抱歉,我没有正确粘贴我的主题模型,我已经更新了我的帖子。我正在样式表类中使用它。 - Hanpan
6个回答

319

移除导入Theme,并直接使用模型名称的字符串。

theme = models.ForeignKey('themes.Theme')

14
实际上需要使用 'themes.Theme',因为它位于另一个应用程序中。 - Daniel Roseman
啊,这个方法可行了,之前我只尝试了'主题',但没有起效果。谢谢。以这种方式进行查询会有性能损耗吗?如果可能的话,我想保持我的查找非懒加载 :) - Hanpan
@Daniel: 更新了。 @Hanpan: 是的,只有一次。 - Ignacio Vazquez-Abrams

87

在Django 1.7之前:

使用django.db.models中设计用于延迟模型导入的get_model函数。

from django.db.models import get_model
MyModel = get_model('app_name', 'ModelName')

根据您的情况:

from django.db.models import get_model
Theme = get_model('themes', 'Theme')

现在您可以使用主题

对于Django 1.7+:

from django.apps import apps
apps.get_model('app_label.model_name')

13
在Django 1.7及以上版本中,使用apps.get_model(app_label, model_name)apps.get_model('app_label.model_name')获取模型。 - phoibos
@phoibos 我可以确认在 Django 3.2+ 中仍然是正确的。 - Harlin

59

在任何地方都没有充分详细地提到如何正确构建ForeignKey内部的字符串以引用不同应用中的模型,这是我从未见过的内容。 这个字符串需要是app_label.model_name。 而且,非常重要的是,app_label并不是INSTALLED_APPS中的整行内容,而只是其中的最后一个组件。 因此,如果您的INSTALLED_APPS看起来像这样:

INSTALLED_APPS = (
...
    'path.to.app1',
    'another.path.to.app2'
)

如果要在app1模型中包含对app2模型的ForeignKey,您必须执行以下操作:

app2_themodel = ForeignKey('app2.TheModel')

在遇到循环导入问题时,我花费了相当长的时间来解决它(所以我不能直接使用from another.path.to.app2.models import TheModel),在我偶然发现这个方法之前,谷歌/stackoverflow都没有提供帮助(所有的例子都是单一组件应用程序路径),因此希望这篇文章能对其他django新手有所帮助。


52

5
还有一种单参数快捷语法:apps.get_model('your_app_name.YourModel'),在map等情况下非常方便。 - Taylor D. Edmiston

0

我遇到了同样的问题,但是当我使用MyModel = get_model('app_name', 'ModelName')时,我得到了一个新的错误'raise AppRegistryNotReady("Models aren't loaded yet.")'

我尝试了这个页面上的所有其他方法,但是没有一个对我起作用。 我解决它的方法是在类中使用:MyModel = get_model('app_name', 'ModelName')而不是在类外部。


请您能否详细说明一下? - MrObjectOriented
在models.py中: from django.apps import apps然后我定义了一个保存方法,其中包含: Cart = apps.get_model(app_label='Carts', model_name='Cart') 这使我能够从其他地方导入另一个Django模型。 - ryansl39

-2
这就是我通过指定'app_name.model_name'和TYPE_CHECKING来解决循环问题的方法。
profile app's models.py
   from typing import TYPE_CHECKING
   if TYPE_CHECKING:
     from team.models import Team

   team = models.ForeignKey('team.Team',...)

team app's models.py  
  Class Team
    name = models.CharField(...) 
    head = models.ForeignKey('profile.Profile',...)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接