当通过符号链接访问文件时,如何正确使用Django的manage.py?

4 投票
1 回答
1960 浏览
提问于 2025-04-16 16:56

问题

当我尝试运行我自定义的 Django 管理命令(send_notify_emails)时,出现了以下错误:

$ python web_apps/manage.py send_notify_emails
Traceback (most recent call last):
  File "web_apps/manage.py", line 11, in <module>
    execute_manager(settings)
  File "/usr/lib/python2.7/site-packages/django/core/management/__init__.py", line 436, in execute_manager
    setup_environ(settings_mod)
  File "/usr/lib/python2.7/site-packages/django/core/management/__init__.py", line 419, in setup_environ
    project_module = import_module(project_name)
  File "/usr/lib/python2.7/site-packages/django/utils/importlib.py", line 35, in import_module
    __import__(name)
ImportError: No module named my_django_app-1.0

背景

我有一个 Django 网站,里面有两个应用。这个网站的目录路径是 /srv/web_apps,里面包含了应用模块的目录,还有 settings.pyurls.pymanage.py 文件。这个路径是一个符号链接,指向 /usr/share/my_django_app-1.0,这个目录是一个生产版本的 svn export。这样我就可以通过简单地移动符号链接到新的生产版本路径来更改我的应用版本,如果需要的话,也可以轻松地切换回早期的版本。

我的 django.wsgi 文件将 /srv/srv/web_apps 添加到 Python 的路径中,这样 mod_wsgi 就能找到我的设置文件和 URL 文件,以及应用模块。

唯一出现 my_django_app-1.0 的地方就是这个目录路径,它并没有出现在我的 settings.py 文件中或其他地方,所以 Django 一定是从路径中获取模块名称的。

看起来发生的情况是,Django 通过跟随符号链接来解析我的应用的包名,而使用的是目标文件夹的名称,而不是符号链接本身。当我运行 manage.py 时,Django 尝试导入 my_django_app-1.0,而实际上它应该导入的是 web_apps

1 个回答

3

我有一个Django网站,里面有两个应用。这个网站的目录路径是/srv/web_apps,这里包含了应用模块的目录,还有settings.py、urls.py和manage.py文件。这个路径是一个符号链接,指向/usr/share/my_django_app-1.0,这里是一个生产版本的svn导出。这样我就可以通过简单地移动这个符号链接到新版本的路径,来轻松更换我的应用版本,如果需要的话,也可以很方便地切换回之前的版本。

你所描述的情况正是人们为什么喜欢使用virtualenv的原因。我建议你看看mod_wsgi虚拟环境

问题在于__file__返回的是符号链接的相对路径,这取决于它是从哪里被导入的(在一个符号链接的路径内..),所以它会报告它的“家”在哪里。因为目录是模块的基本结构,如果你有一个包含__init__.py的目录,那么无论这个目录叫什么名字,导入时它就会被称为这个名字

你可能可以覆盖这种行为,但那样做并不是正确的方式——可以看看virtualenv,或者为每个版本设置单独的目录,使用下划线而不是点。例如myApp_1_0_0,等等。

考虑以下场景:

mkdir real_directory
ln -s real_directory symlink_directory
cat >>real_directory/__init__.py <<EOF
import os
print
print '__name__ == %s' % (__name__)
print '__file__ == %s' % (__file__)
print ' abspath == %s' % os.path.abspath(__file__)
print 'realpath == %s' % os.path.realpath(os.path.abspath(__file__))
print
EOF

python -c "import real_directory"

__name__ == real_directory
__file__ == real_directory/__init__.py
 abspath == /Users/nar/pt/real_directory/__init__.py
realpath == /Users/nar/pt/real_directory/__init__.py

python -c "import symlink_directory"

__name__ == symlink_directory
__file__ == symlink_directory/__init__.pyc
 abspath == /Users/nar/pt/symlink_directory/__init__.pyc
realpath == /Users/nar/pt/real_directory/__init__.pyc

撰写回答