我有一个具有以下结构的django应用程序:
.
├── admin.py
├── apps.py
├── Business
├── __init__.py
├── migrations
├── models
├── __pycache__
├── templates
├── tests.py
├── urls.py
└── views
在模型文件夹中,我有一个__init__.py
文件,其中包含以下代码:
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
from web.Business.rockynodeZabbix import Zabbix
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_zabbix_group(sender, instance=None, created=False, **kwargs):
if created:
Zabbix.component("HostGroup").create(instance.id)
问题是我无法在模型中导入我的app web
模块方法,因为Business
模块中的几个类调用了model
模块:
import web.models as models
如果我在模型中导入应用模块web.Business.xxxx
,我会收到以下错误:
File "/Users/kheshav/Linux_projects/rockynode.io/App/web/models/__init__.py", line 11, in <module>
from web.Business.rockynodeZabbix import Zabbix
File "/Users/kheshav/Linux_projects/rockynode.io/App/web/Business/__init__.py", line 1, in <module>
from .test import test
File "/Users/kheshav/Linux_projects/rockynode.io/App/web/Business/test.py", line 1, in <module>
import web.models as models
AttributeError: module 'web' has no attribute 'models
如何在模型中调用我的app模块功能,因为我想在创建用户时触发它。
答案 0 :(得分:1)
你认为我是一个典型的循环依赖问题。这些通常很难诊断,因为你会得到非常奇怪的错误。不幸的是,没有Python回溯说“循环依赖!”
让我们把它分解。
在models/__init__.py
你说过你有以下内容:
from web.Business.rockynodeZabbix import Zabbix
所以,当它到达这一行时,Python所做的就是停止并执行以下操作
查找web.Business.__init__
并执行所有顶级声明,然后将web.Business
添加到导入的模块中。
查找web.Business.rockynodeZabbix
并执行所有顶级声明,并将web.Business.rockynodeZabbix
添加到导入的模块,并Zabbix
添加到此模块的命名空间。
现在,假设您在web.Business.rockynodeZabbix
中有类似的内容:
from web.models.some_module import some_thing
好吧,现在我们有一个周期。我们已经导入web.models.__init__
。作为导入的一部分,我们开始关注web.Business...
。 Python已经将web.models.__init__
添加到导入的模块中,因为它是我们开始使用的模块,换句话说,就目前的导入行而言,它认为我们已经完成了。
稍后,当您想要使用循环导入模块中的某些属性时,Python通常会告诉您它不存在。这是循环依赖的标志。它停止并保存并且从未完成,因此它通常会在您想要使用未完全导入的命名空间中的内容的任何地方抛出AttributeError
。
这是一个不是每个人都同意的观点(例如,你曾经使用过Flask吗?):
循环依赖是一个架构问题,必须不惜一切代价避免它们
要解决此问题,您需要使模块不以这种方式相互导入。
例如,把它想象成一棵树。您可以将models
视为“低级别”。然后,树中更高的其他内容可以导入models
但models
除了更低级别的实用程序和内容之外无法导入任何内容。
然后,您将移动models
中的代码,将代码从树中的更高位置导入到其所属的另一个模块中。
此外,同一级别的节点不应该彼此了解。
在模块中放置代码时,请记住树结构:
最后一点意见:在Django中创建糟糕的架构设计很容易(不是Django的错误),因为我们经常在我们的models
模块中放入大量的应用程序逻辑。然后,整个项目的内容开始导入这些models
模块,然后相互交叉导入。警惕这个设计陷阱。