如何通过“manage.py shell”使用交互式解释器重新载入Django模型模块?
我知道如何在常规的Python解释器会话中重新加载常规的Python模块。 这个问题logging了如何做得很好:
如何卸载(重新加载)Python模块?
出于某种原因,我在Django的“manage.py shell”解释器会话中遇到了麻烦。 要重新创build我的问题,请在这里find基本的Django教程:
编写你的第一个Django应用程序,第1部分
创build“民意调查”应用程序和“民意调查”类后,通过“manage.py shell”启动解释器,并导入“民意调查”应用程序。
import polls.models as pm
创build一个新的“民意调查”对象:
p = pm.Poll()
一切都很好,迄今为止。 现在回到你的源代码并添加任意的方法或属性。 例如,我添加了:
def x(self): return 2+2
现在回到解释器并重新加载模块:
reload(pm)
现在尝试使用你的新方法或属性:
p1 = pm.Poll() p1.x()
你会得到这个消息:
'Poll' object has no attribute 'x'
是什么赋予了? 我也试着重新运行import命令,使用不同的语法导入模块,删除所有对“Poll”对象的引用或“Poll”类。 我也用IPython解释器和普通的Python(v2.6)解释器试了这个。 似乎没有任何工作。
在常规解释器会话中使用与任意Python模块相同的技术是完美的。 我似乎无法让它在Django的“shell”会话中工作。
顺便说一下,如果它有什么区别,我在Ubuntu 9.04机器上做这个。
那么,我想我必须回答这个问题。 问题在于,Django将其模型caching在一个名为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
我把所有这些放在我的Django站点的根目录下的一个名为reloadmodels.py的单独文件中。 使用IPython,我可以通过运行来重新加载所有的东西:
%run ~/mysite/reloadmodels.py
假设你的项目是这样设置的
- 项目名称:书店
- 应用程序名称:货架
- 型号名称:图书
第一次加载
from bookstore.shelf.models import Books
随后重新加载
import bookstore;reload(bookstore.shelf.models);from bookstore.shelf.models import Books
就我而言,上面的解决scheme都没有自己的工作, 这个线程本身并没有太大的帮助,但是在结合了这些方法之后,我设法在shell_plus中重新加载了我的模型:
- 对模型进行更改(MyModel)
- 删除
models.pyc
-
干净的Django模型caching(像这里 ):
from django.db.models.loading import AppCache cache = AppCache() from django.utils.datastructures import SortedDict cache.app_store = SortedDict() cache.app_models = SortedDict() cache.app_errors = {} cache.handled = {} cache.loaded = False
-
像这里重新加载模型
reload(project.app.models) from project.app.models import MyModel
您也可以使用以下命令使用django-extensions项目:
manage.py shell_plus --notebook
这将在您的Web浏览器上打开IPython笔记本,而不是IPython shell解释器。 在那里写你的代码,并运行它。
当你改变你的模块,只需点击网页菜单项“内核 – >重新启动”
现在重新运行代码使用您的修改模块。
ipython控制台使用每个reload()
expression式进行深度重载 ; 当然也增加了很多其他有用的东西。
我在2016年的解决scheme(将来可能会改变)
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'
缺点:1.需要手动运行代码
%autoreload 2
因为django_extension 1.7不支持运行任意代码。 可能在未来的版本中有这个function。
笔记:
- 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()。
在导入任何代码之前启用IPython自动重载扩展:
%load_ext autoreload %autoreload 2
我使用它与常规的Djangoshell和它完美的作品,虽然它有一些限制:
*注意事项:
以可靠的方式重新加载Python模块通常是困难的,并且可能发生意想不到的事情。 %autoreload试图通过用新版本replace模块中的函数代码对象和类的一部分来解决常见的陷阱。 这使得以下的工作:
- 当'xxx'重新加载时,通过'from xxx import foo'导入的函数和类会升级到新版本。
- 类的方法和属性在重载时升级,因此在重载之前创build的对象“c”上调用“c.foo()”会导致执行“foo”的新代码。
一些已知的剩余警告是:
- replace代码对象并不总是成功:将类中的@property更改为普通方法或将方法更改为成员variables可能会导致问题(但仅在旧对象中)。
- 在重新加载之前从模块中删除的function(例如,通过猴子修补)不会升级。
- C扩展模块无法重新加载,所以无法自动加载。*
来源: https : //ipython.org/ipython-doc/3/config/extensions/autoreload.html#caveats
另一个不错的select是将你的代码写在一个单独的脚本中,并将其发送到django shell,如下所示:
manage.py shell < my_script.py
我无法得到任何上述解决scheme的工作,但我想出了一个解决方法,重新加载我的django项目(例如一个functions.py
或views.py
模块)中的任何其他非模型模块。
-
创build一个名为
reimport_module.py
的文件。 我把它存储在我的开发机器上的django项目的local/
文件夹中。# Desc: Imports the module with the name passed in, or imports it for first # time if it hasn't already been imported. # # Purpose of this script is to speed up development of functions that # are written in an external editor then tested in IPython. # # Without this script you have to exit & reenter IPython then redo # import statements, definitions of local variables, etc. # # Note: doesn't work for Django models files, because Django caches # them in a structure called AppCache. # # Args: module to reload (string) import sys module_to_reload = sys.argv[1] # Attempt to pop module try: sys.modules.pop(module_to_reload) print 'reimporting...' except KeyError: print 'importing for first time...' # (re)import module import_str = 'from {0} import *'.format(module_to_reload) exec(import_str)
-
启动shell plus(使用embedded式IPython shell):
python manage.py shell_plus
-
使用以下命令导入您正在开发的模块:
%run local/reimport_module.py 'your.module'
-
使用IPython来testing模块中的函数。
- 在外部编辑器中更改模块。
-
使用以下命令重新导入模块,而不必退出并重新inputIPython:
%run local/reimport_module.py 'your.module'
注意:这个命令已经在步骤3中使用了,所以你可以input
%run
然后向上箭头自动完成它。
从Seti Volkylany和pv
- 安装IPython:
pip install ipython
- 运行
python manage.py shell
:在一行开头的符号现在应该是In [1]:
在cmd里是>>>
) - 运行
ipython profile create
-
进入
~/.ipython/profile_default/ipython_config.py
并在文本编辑器中打开它,并在末尾添加这两行:c.InteractiveShellApp.extensions = ['autoreload']
c.InteractiveShellApp.exec_lines = ['%autoreload 2']
你现在可以运行python manage.py shell
,编辑你的模型而不必写%autoreload 2