Django项目(apache,mod_wsgi)无法导入命名空间包
在用pip从bitbucket仓库安装django-piston的时候,我发现了一些奇怪的事情(输出的第一行缩进部分):
$ pip install hg+http://bitbucket.org/jespern/django-piston
Downloading/unpacking hg+http://bitbucket.org/jespern/django-piston
Cloning Mercurial repository http://bitbucket.org/jespern/django-piston to /tmp/pip-v1h8Sh-build
Running setup.py egg_info for package from hg+http://bitbucket.org/jespern/django-piston
Installing collected packages: django-piston
Running setup.py install for django-piston
Skipping installation of [venv]/lib/python2.6/site-packages/piston/__init__.py (namespace package)
Installing [venv]/lib/python2.6/site-packages/django_piston-0.2.3rc1-py2.6-nspkg.pth
Successfully installed django-piston
Cleaning up
Pip不会安装piston的__init__.py
文件,这表示'piston'被指定为setup.py
中的一个namespace_packages
。
接着,我查看了“django_piston-0.2.3rc1-nspkg.pth”文件,发现里面似乎在尝试创建“虚拟包”:
# File: [virtualenv]/lib/python2.6/site-packages/django_piston-0.2.3rc1-py2.6-nspkg.pth
# Originally all on one line; broken apart here for readability.
import sys,new,os;
p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('piston',));
ie = os.path.exists(os.path.join(p,'__init__.py'));
m = not ie and sys.modules.setdefault('piston',new.module('piston'));
mp = (m or []) and m.__dict__.setdefault('__path__',[]);
(p not in mp) and mp.append(p)
我明白它在干什么;它基本上是在创建一个“假模块”,也就是piston应该在的地方,这个假模块实际上是把piston的所有子模块聚合在一起。
这在命令行操作中似乎没问题(我可以在django的shell中导入piston [虽然它的显示是<module 'piston' (built-in)>
],而且在运行服务器时也一切正常),但是我的项目在apache mod_wsgi上运行时,每个页面都会抛出500错误,因为它提示“找不到模块piston.handler”。
我已经排除了python路径的问题;所有尝试中site-packages目录都在路径里。我不知道还有什么其他原因会导致这种情况,有什么想法吗?
1 个回答
经过进一步查找,我在 mod_wsgi 的文档 中找到了答案:
不过,作为一个额外的步骤,文档中提到的 WSGI 脚本文件需要进行修改,以便在基础环境上叠加应用程序的虚拟环境。这可以通过在 WSGI 脚本文件的最开始添加以下内容来实现:
import site site.addsitedir('/usr/local/pythonenv/PYLONS-1/lib/python2.5/site-packages')
需要注意的是,在这种情况下,必须指定虚拟环境中 'site-packages' 目录的完整路径,而不仅仅是虚拟环境的根目录。
使用 'site.addsitedir()' 和简单地将目录添加到 'sys.path' 是有点不同的,因为这个函数会打开目录中的任何 '.pth' 文件并处理它们。这是必要的,以确保与 Python eggs 相关的特殊目录会自动添加到 'sys.path' 中。
在我的 wsgi 脚本中添加 site.addsitedir
调用(而不是像之前那样添加到 sys.path
)解决了所有问题。