首页 > 解决方案 > 将 django 服务器作为子包执行

问题描述

我正在尝试将 Django 服务器作为项目的一部分运行,到目前为止,该项目还有另一个包。如果仅出于学习目的,我想暂时保持这种状态,而不是合并核心和网络包。我看过类似的问题,但没有找到解决我的具体问题的方法

下面列出的树是在根项目文件夹中运行以下命令的结果:

django-admin startproject web

.
├── __init__.py
├── core
│   ├── __init__.py
│   ├── __pycache__
│   │   └── __init__.cpython-38.pyc
│   ├── server.py
│   └── task_manager
│       ├── __init__.py
│       ├── __pycache__
│       └── main.py
├── test
├── venv
│   ├...
│   └── pyvenv.cfg
└── web
    ├── __init__.py
    ├── __pycache__
    │   ...
    ├── db.sqlite3
    ├── manage.py
    └── web
        ├── __init__.py
        ├── __pycache__
        ├── asgi.py
        ├── settings.py
        ├── urls.py
        └── wsgi.py

由于我希望 Django 服务器能够访问外包,我的理解是我必须 cd 进入基础项目目录,并像这样运行 Web 服务器:

python -m web.manage runserver

由于默认情况下 django-admin createproject 创建的文件包含绝对包引用,因此我将“web.XYZ”更改为“web.web.XYZ”引用。

我的问题:如果我只是简单地运行上述命令来执行 runserver,我会收到以下导入错误:

ModuleNotFoundError: No module named 'web.web'

经过一番调查,我发现我可以使用 core.XYZ 和 web.web.XYZ 从同级包和当前包中导入两个文件。实际上,像这样修改默认的 manage.py 代码:

import os
import sys

import web.web.settings
print('This prints just fine')

def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'web.web.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()

产生以下输出:

...:ProjectMgmt ...$ python -m web.manage runserver
This prints just fine
Traceback (most recent call last):
  File "/Volumes/ProjectMgmt/web/manage.py", line 6, in <module>
    import web.web.settings
ModuleNotFoundError: No module named 'web.web'

这使我认为“某事”正在重新加载 manage.py 模块,而“某事”发生在两者之间,导致脚本无法找到正确的包结构。挖掘 Django 代码,我在 execute_from_command_line 执行的代码中发现了以下内容(注意对 autoreload.check_errors 的调用),它本身在 manage.py 中调用:

if settings.configured:
    # Start the auto-reloading dev server even if the code is broken.
    # The hardcoded condition is a code smell but we can't rely on a
    # flag on the command class because we haven't located it yet.
    if subcommand == 'runserver' and '--noreload' not in self.argv:
        try:
            autoreload.check_errors(django.setup)()
        except Exception:
            # The exception will be raised later in the child process
            # started by the autoreloader. Pretend it didn't happen by
            # loading an empty list of applications.
            apps.all_models = defaultdict(OrderedDict)
            apps.app_configs = OrderedDict()
            apps.apps_ready = apps.models_ready = apps.ready = True

    # In all other cases, django.setup() is required to succeed.
    else:
        django.setup()

将 --noreload 参数添加到我的 runserver 命令并从基本项目文件夹执行它实际上可以很好地启动服务器,并且没有更多的导入错误。

python -m web.manage runserver --noreload

我的问题:为什么会发生这种情况,无论如何要避免使用 --noreload ?这感觉很hacky。

标签: pythondjangopackagepython-3.8

解决方案


推荐阅读