如何在Django shell中重新加载模块?
我正在使用Django,并且经常使用Django的命令行工具(shell)。最烦人的地方是,当我修改代码时,Django服务器会自动重载,但命令行工具却不会。所以每次我修改一个正在测试的方法时,都得退出命令行工具,然后重新启动它,还得重新导入我需要的所有模块,重新初始化所有需要的变量等等。虽然iPython的历史记录可以帮我省去很多输入,但这还是很麻烦。有没有办法让Django的命令行工具像Django开发服务器那样自动重载呢?
我知道有reload()这个方法,但我导入了很多模型,通常使用的是from app.models import *
这种写法,所以reload()对我帮助不大。
12 个回答
我的解决办法是先写好代码,然后把它保存到一个文件里。接着我会用下面的命令:
python manage.py shell < test.py
这样我就可以修改代码,保存后再运行这个命令,直到我把想要修复的东西修好为止。
我建议使用 IPython 的 自动重载扩展。
./manage.py shell
In [1]: %load_ext autoreload
In [2]: %autoreload 2
从现在开始,所有导入的模块在执行之前都会被刷新。
In [3]: from x import print_something
In [4]: print_something()
Out[4]: 'Something'
# Do changes in print_something method in x.py file.
In [5]: print_something()
Out[5]: 'Something else'
即使在输入 %load_ext autoreload
命令之前导入的东西也能正常工作。
./manage.py shell
In [1]: from x import print_something
In [2]: print_something()
Out[2]: 'Something'
# Do changes in print_something method in x.py file.
In [3]: %load_ext autoreload
In [4]: %autoreload 2
In [5]: print_something()
Out[5]: 'Something else'
你还可以通过 %aimport
命令来防止某些导入被刷新,并有三种自动重载策略:
%autoreload
- 现在自动重新加载所有模块(除了那些被 %aimport 排除的)。
%autoreload 0
- 禁用自动重载。
%autoreload 1
- 每次在执行输入的 Python 代码之前,重新加载所有通过 %aimport 导入的模块。
%autoreload 2
- 每次在执行输入的 Python 代码之前,重新加载所有模块(除了那些被 %aimport 排除的)。
%aimport
- 列出哪些模块会被自动导入,哪些不会。
%aimport foo
- 导入模块 ‘foo’,并标记为在 %autoreload 1 中自动重载。
%aimport -foo
- 标记模块 ‘foo’ 不进行自动重载。
这对我来说通常很好用,但也有一些注意事项:
- 替换代码对象并不总是成功:将类中的 @property 改为普通方法,或者将方法改为成员变量可能会导致问题(但只在旧对象中)。
- 在模块重新加载之前被移除的函数(例如通过猴子补丁)不会被升级。
- C 扩展模块无法重新加载,因此也无法自动重载。
我建议使用django-extensions这个项目,就像dongweiming提到的那样。不过,不要仅仅使用'shell_plus'这个管理命令,而是用:
manage.py shell_plus --notebook
这会在你的网页浏览器上打开一个IPython笔记本。在那里,你可以在一个单元格里写代码,包括导入的库等等,然后运行它。
当你修改了模块后,只需点击笔记本菜单中的'Kernel->Restart'。
这样,你的代码就会使用你修改过的模块了。