Django模型无法调用app模块方法

时间:2017-10-20 18:43:54

标签: python django django-models

我有一个具有以下结构的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模块功能,因为我想在创建用户时触发它。

1 个答案:

答案 0 :(得分:1)

你认为我是一个典型的循环依赖问题。这些通常很难诊断,因为你会得到非常奇怪的错误。不幸的是,没有Python回溯说“循环依赖!”

让我们把它分解。

models/__init__.py你说过你有以下内容:

from web.Business.rockynodeZabbix import Zabbix

所以,当它到达这一行时,Python所做的就是停止并执行以下操作

  1. 查找web.Business.__init__并执行所有顶级声明,然后将web.Business添加到导入的模块中。

  2. 查找web.Business.rockynodeZabbix并执行所有顶级声明,并将web.Business.rockynodeZabbix添加到导入的模块,并Zabbix添加到此模块的命名空间。

  3. 现在,假设您在web.Business.rockynodeZabbix中有类似的内容:

    from web.models.some_module import some_thing
    

    好吧,现在我们有一个周期。我们已经导入web.models.__init__。作为导入的一部分,我们开始关注web.Business...。 Python已经将web.models.__init__添加到导入的模块中,因为它是我们开始使用的模块,换句话说,就目前的导入行而言,它认为我们已经完成了。

    稍后,当您想要使用循环导入模块中的某些属性时,Python通常会告诉您它不存在。这是循环依赖的标志。它停止并保存并且从未完成,因此它通常会在您想要使用未完全导入的命名空间中的内容的任何地方抛出AttributeError

    这是一个不是每个人都同意的观点(例如,你曾经使用过Flask吗?):

    循环依赖是一个架构问题,必须不惜一切代价避免它们

    要解决此问题,您需要使模块以这种方式相互导入。

    例如,把它想象成一棵树。您可以将models视为“低级别”。然后,树中更高的其他内容可以导入modelsmodels除了更低级别的实用程序和内容之外无法导入任何内容。

    然后,您将移动models中的代码,将代码从树中的更高位置导入到其所属的另一个模块中。

    此外,同一级别的节点不应该彼此了解。

    在模块中放置代码时,请记住树结构:

    1. 没有模块应该从树中的较高位置导入任何内容。
    2. 没有模块应该从树中与自身相同级别的未连接节点导入任何内容(难以强制执行,但如果您可以这样组织则非常有用)。
    3. 最低级别的资料应从您的项目中导入 nothing 。这些将始终是最安全的模块,可以在其他地方导入。
    4. 顶部的模块将其下方的所有内容捆绑在一起。
    5. 最后一点意见:在Django中创建糟糕的架构设计很容易(不是Django的错误),因为我们经常在我们的models模块中放入大量的应用程序逻辑。然后,整个项目的内容开始导入这些models模块,然后相互交叉导入。警惕这个设计陷阱。