如何通过“manage.py shell”使用交互式解释器重新加载Django模型模块?
如何通过“manage.py shell”使用交互式解释器重新加载Django模型模块?
我知道如何在普通的Python解释器会话中重新加载一个普通的Python模块。这个问题很好地记录了如何做到这一点:
出于某种原因,我在Django的“manage.py shell”解释器会话中做到这一点时遇到了困难。为了重新创建我的问题,请在这里找到基本的Django教程:
在创建“投票(polls)”应用程序和“Poll”类之后,通过“manage.py shell”启动解释器并将“投票”应用程序导入其中。
import polls.models as pm
创建一个新的“投票”对象:
p = pm.Poll()
到目前为止,一切都很好。现在回到你的源代码并添加任意的方法或属性。例如,我添加了:
def x(self): return 2+2
现在回到解释器并“重新加载”模块:
reload(pm)
现在尝试使用您的新方法或属性:
p1 = pm.Poll() p1.x()
你会得到这个消息:
'Poll' object has no attribute 'x'
怎么回事?我也尝试重新运行导入命令,使用不同的语法导入模块,删除所有对任何“投票”对象或“投票”类的引用。我还尝试了使用IPython解释器和普通Python(v2.6)解释器。似乎什么都没有用。
在普通解释器会话中使用同样的技术与任意Python模块完美地运作。我似乎无法在Django的“shell”会话中使其正常工作。
顺便说一下,如果有任何不同,我是在Ubuntu 9.04机器上完成这个任务的。
我在2016年时的解决方案(未来可能会更改)
1. 安装django_extension
2. 添加以下设置:
SHELL_PLUS = 'ipython' IPYTHON_ARGUMENTS = [ '--ext', 'autoreload', ]
3. 运行shell
./manage.py shell_plus
查看结果:
模型示例
class Notification(models.Model): ........ @classmethod def get_something(self): return 'I am programmer'
在shell中
In [1]: Notification.get_something() Out[1]: 'I am programmer'
对模型进行更改
@classmethod def get_something(self): return 'I am Python programmer'
在shell中
# shell does not display changes In [2]: Notification.get_something() Out[2]: 'I am programmer'
在shell中。这是一种魔法
# configure extension of ipython In [3]: %autoreload 2
在shell中
# try again - all worked In [4]: Notification.get_something() Out[4]: 'I am Python programmer'
再次进行更改
@classmethod def get_something(self): return 'I am full-stack Python programmer'
在shell中
# all worked again In [5]: Notification.get_something() Out[5]: 'I am full-stack Python programmer'
缺点:
%autoreload 2
因为django_extension 1.7没有支持运行任意代码。也许在将来的版本中会有这个功能。
注意事项:
- Django 1.10
- Python 3.4
- django_extension 1.7.4
- 基于https://django-extensions.readthedocs.io/en/latest/shell_plus.html和http://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html
- 注意。如果尝试更改使用了super()的代码,则可能产生错误。
好的,我认为我必须回答这个问题。问题在于 Django 将其模型缓存到一个叫 AppCache 的单例(类似结构)中。基本上,要重新加载 Django 模型,您需要先重新加载和重新导入存储在 AppCache 中的所有模型模块。然后您需要清除 AppCache。以下是代码:
import os from django.db.models.loading import AppCache cache = AppCache() curdir = os.getcwd() for app in cache.get_apps(): f = app.__file__ if f.startswith(curdir) and f.endswith('.pyc'): os.remove(f) __import__(app.__name__) reload(app) from django.utils.datastructures import SortedDict cache.app_store = SortedDict() cache.app_models = SortedDict() cache.app_errors = {} cache.handled = {} cache.loaded = False
我将所有这些代码放在名为 reloadmodels.py 的单独文件中,放在 Django 站点的根目录中。使用 IPython,我可以通过运行以下命令来重新加载所有内容:
%run ~/mysite/reloadmodels.py