在Django项目中导入应用程序

5

我在我的Django项目中的一个应用程序导入另一个应用程序时遇到了问题。

我知道关于这个主题有许多问题/答案,相信我,我阅读了很多,甚至包括一些有关Python导入的内容。

这是我的项目树(我将放置真实的文件夹名称):

was/ # full path from my computer /home/user/project/was
....was/ #django project created by django-admin startproject 'was'
    ....manage.py
    ....artists/ #first app
        ....migrations/
        ....templates/
        ....__init__.py 
        ....other_python_files.py
    ....crew/ #second app    
        ....migrations/
        ....templates/
        ....__init__.py
        ....some_files.py
    ....was/ # folder containing settings.py, main urls.py
        ....__init__.py

我的第一个项目(/home/user/project/was)包含了虚拟环境生成的文件夹(python3.4)。

我在PyCharm中检查了我的Python路径sys.path和我的项目结构,发现有/home/user/project/was。

在PyCharm中这样做时,自动补全功能工作得很好:

from ..crew.models import MyClass #here i'm in a artists app file

但是当我导入应用程序时,出现了ValueError:尝试相对于顶级包进行相对导入

现在,同样的情况,在艺术家应用程序中导入一个乘组类,但是:

from was.crew.models import MyClass

在PyCharm中,自动完成功能正常,但这一次我遇到了经典的ImportError:no name was.crew

我发现通过在我的settings.py文件中添加以下行可以解决问题:

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR)) # add this line

请注意,BASE_DIR已经存在于设置中。 现在我可以这样做:
from crew.models import MyClass

在这里我没有错误(在Pycharm中更改一些设置使自动完成起作用)。

这个方法可以,但我真的很想知道为什么要添加这行代码以及为什么我的前两次尝试不起作用。

我对包、pythonpath等有点迷茫(这就是为什么我在模式中指定了所有的__init__.py文件)。

难道 from ..anotherapp.models import Class 不需要在settings.py中进行任何修改?

无论如何,我应该保留我的解决方案还是不好吗?

感谢您提前给予任何回复。

附注:请注意,我已经尝试在我的第一个和第二个文件夹中添加了__init__.py文件,但没有成功。

4个回答

4
在Django项目中,您不需要提供从根目录到项目目录的路径。此外,BASE_DIR是您的Django项目的路径,在导入Django中的任何应用程序时,只需使用其名称即可。
因此,您的导入将是:
from crew.models import MyClass

是的,现在我已经删除了Python路径中的条目(我强制添加的那个),现在它可以正常工作了。不知道为什么,但是通过编写from crew.models import MyClass可以很好地工作。感谢您的回答。 - Bestasttung
@Bestasttung 不客气。这能正常工作是因为你的 Django 项目中 settings.py 中的 BASE_DIR 映射了 Django 应用程序的路径。请查看 Django 文档 链接 - Jaysheel Utekar

2

一个可运行的示例项目。

项目结构

test_project/
  test_project/
    settings.py
    urls.py
    wsgi.py 
  app1/
    models.py
  app2/
    models.py

app1/models.py

from django.db import models

class Restaurant(models.Model):
    name = models.CharField(max_length=255)

app2/models.py

from django.db import models
from app1.models import Restaurant

class Waiter(models.Model):
    restaurant = models.ForeignKey(Restaurant)
    name = models.CharField(max_length=255)

在您的情况下,from ..crew.models import MyClassfrom crew.models import MyClass 都应该可以使用。我的猜测是您(或 PyCharm)在 app 目录中尝试运行某个文件或导入模块。当前目录(无论它是什么意思)应该是由 django-admin.exe 创建的那个 was 目录。希望能有所帮助。

实际上,当我启动服务器并转到localhost:8000时,错误会触发。是的,它应该工作(实际上在pycharm中可以检索我的应用程序树),但是Django会引发错误。这可能是虚拟环境Python库放置在文件夹树中太高的问题吗? - Bestasttung
我从Python路径中删除了该条目,并在不使用设置中的代码行的情况下运行app1.models,感谢您的回答! - Bestasttung

0
一个更好的步骤近似是避免循环引用,而是使用django.apps.get_model
from django.apps import apps as django_apps

在你的代码片段中

MyModel = django_apps.get_model("AppName","MyModel")

或者

MyModel = django_apps.get_model("AppName.MyModel")

当在将模型导入到另一个文件时,最有可能出现循环导入的情况,因此您可以避免导入它,而是使用“AppName.ModelName”来命名。

artist = models.ForeignKey("AppName.Artist")

0

我认为这会对你有所帮助!我曾经为同样的问题苦苦挣扎了几天。我已经把所有的init.py文件放在了正确的位置。最终,我不得不将源代码目录设置为项目目录:

右键单击project_dir,Mark Directory as > Sources Root

它真的有用!


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