【问题标题】:How to import Django models from script started with Popen() from views.py?如何从 views.py 中以 Popen() 开头的脚本导入 Django 模型?
【发布时间】:2021-06-06 11:34:51
【问题描述】:

当某个请求到达我的 django 服务器时,我想在不同的进程中启动一个 python 脚本。 我可以成功启动它,但它的导入失败。

在我的 django 应用程序中,我有一个 views.py。 在这我有一个ViewSet 和一个update() 方法,看起来像这样(将sn-p 简化为相关代码):

from . import models # notice this import, which works

def update(self, request, pk=None):
    dirname = os.path.dirname(__file__)
    filename = os.path.join(dirname, 'Process.py')
    p = subprocess.Popen(["python", filename],
                         stdout=sys.stdout, 
                         stdin=subprocess.PIPE)

这按预期工作:当执行导致调用update() 的适当请求时,它会执行Process.py,这是与views.py 位于同一目录中的文件。

Process.py中,我想访问django后端的模型,所以我照着之前做的:

from . import models

# more code here

但我得到了错误:

ImportError: cannot import name 'models'

为什么这个导入在Process.py 中会失败,即使它适用于views.py

我试过了

  • 互联网上的一个建议,应该将环境设置为与子进程相同,如下所示:

    p = subprocess.Popen(["python", filename],
                         env = {'PYTHONPATH': os.pathsep.join(sys.path)}, # this is new
                         stdout=sys.stdout, 
                         stdin=subprocess.PIPE)
    

    但这根本无法启动python:

    Fatal Python error: failed to get random numbers to initialize Python
    
  • 以不同的方式在Process.py 中编写导入语句:

    from models import stuff
    

    奇怪的是,这确实导入了models.py(耶!)但在兔子洞的深处失败了:

    ModuleNotFoundError: No module named '<django project name>'
    

    说的兔子洞从models.py 中的第一个模型类开始,然后潜入 django 代码,最后是一些引导程序:

    Traceback (most recent call last):
    File "<path to django app>\Process.py", line 1, in <module>
      from models import stuff
    File "<path to django app>\models.py", line 3, in <module>
      class <some model class>(models.Model):
    File "<path to conda environment>\lib\site-packages\django\db\models\base.py", line 108, in __new__
      app_config = apps.get_containing_app_config(module)
    File "<path to conda environment>\lib\site-packages\django\apps\registry.py", line 253, in get_containing_app_config
      self.check_apps_ready()
    File "<path to conda environment>\lib\site-packages\django\apps\registry.py", line 135, in check_apps_ready
      settings.INSTALLED_APPS
    File "<path to conda environment>\lib\site-packages\django\conf\__init__.py", line 82, in __getattr__
      self._setup(name)
    File "<path to conda environment>\lib\site-packages\django\conf\__init__.py", line 69, in _setup
      self._wrapped = Settings(settings_module)
    File "<path to conda environment>\lib\site-packages\django\conf\__init__.py", line 170, in __init__
      mod = importlib.import_module(self.SETTINGS_MODULE)
    File "<path to conda environment>\lib\importlib\__init__.py", line 126, in import_module
      return _bootstrap._gcd_import(name[level:], package, level)
    

    看起来 django 以某种方式干扰了我的导入,但我不确定如何以及如何纠正它们。

如何从以subprocess.Popen(...) 开头的views.py 的python 脚本成功导入(和使用)models.py 应用程序?


来自 cmets

Process.py 是一个普通的 Python 脚本,还是作为 Django 管理命令编写的?

这是一个常规脚本。 我出于调试目的对其进行了修改,如下所示:

import sys
for p in sys.path:
    print(p)

from . import models

如果您从 shell 手动运行脚本会发生什么?同样的错误?

from shell django views.py via Popen()
windows cmd: django-project&gt;python manage.py shell then In [1]: from django-app import Process see above call detail
success ImportError: cannot import name 'models' result
includes django-project path and empty path includes django-project/django-app differences of sys.path

【问题讨论】:

  • Process.py 是普通的 Python 脚本,还是写成 Django Management Command?如果从 shell 手动运行脚本会发生什么?同样的错误?
  • @C14L 只是一个普通的 python 脚本(单独的 import 语句会重现错误)。感谢您的建议。我正在对 django 的命令进行更多研究,based on this anser。我设法创建了一个自定义命令并通过 manage.py 使用工作导入执行它,但是:我将如何将它作为一个单独的进程执行?
  • 我只是在猜测:将PYTHONPATH 保留在上面的示例中,并将["python", filename] 更改为["python", "manage.py", filename]
  • @C14L 你让我走上了正确的道路:根据你的建议,我能够调用我之前提到的Process.py 的 Django-Management-Comment 版本并解决了我的担忧“但是:我将如何将其作为一个单独的进程执行?” - 只需在永远不会返回的句柄方法中执行 while True:,这很好,因为调用仍然包含在 Popen() 中。谢谢。随时发布作为答案。
  • 很高兴它起作用了 :) 我将其添加为答案。

标签: django django-rest-framework python django-models django-rest-framework subprocess modulenotfounderror


【解决方案1】:

Process.py 应该是Django Management Command,以便加载 Django 框架并由 Django 使用model.py

PYTHONPATH 仍然是必需的,以便 Django 知道基目录在哪里。

代替["python", filename],进程可以用["python", "manage.py", filename]启动。

【讨论】:

    【解决方案2】:

    可能您缺少对 Django 应用程序的引用,要从中导入所有模型,您必须在 python 脚本中执行:

    from <django-app-name>.models import *
    

    【讨论】:

    • 不:ModuleNotFoundError: No module named 'django-app-name'
    • 问题仍然存在:与兄弟模块views.py相比,为什么它需要不同的导入?
    • 如果您处理脚本与views.py 和models.py 位于同一级别,则只有“from .import models”应该可以正常工作。你能分享你的项目文件夹结构的打印吗?
    • 我也这么认为。问题是 Django 需要一些初始化/设置/引导才能使 API 等可用。常规脚本存在于该环境之外。没关系,我通过 django 命令解决了这个问题。谢谢你的回答。
    猜你喜欢
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    相关资源
    最近更新 更多