如何通过“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中重新加载了我的模型:

  1. 对模型进行更改(MyModel)
  2. 删除models.pyc
  3. 干净的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 
  4. 像这里重新加载模型

     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。

笔记:

  1. Django 1.10
  2. Python 3.4
  3. django_extension 1.7.4
  4. 基于(主要)在https://django-extensions.readthedocs.io/en/latest/shell_plus.html和http://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html
  5. 警告。 这可能会产生一个错误,如果你尝试改变一个代码在哪里使用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.pyviews.py模块)中的任何其他非模型模块。

  1. 创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) 
  2. 启动shell plus(使用embedded式IPython shell):

    python manage.py shell_plus

  3. 使用以下命令导入您正在开发的模块:

    %run local/reimport_module.py 'your.module'

  4. 使用IPython来testing模块中的函数。

  5. 在外部编辑器中更改模块。
  6. 使用以下命令重新导入模块,而不必退出并重新inputIPython:

    %run local/reimport_module.py 'your.module'

    注意:这个命令已经在步骤3中使用了,所以你可以input%run然后向上箭头自动完成它。

从Seti Volkylany和pv

  1. 安装IPython: pip install ipython
  2. 运行python manage.py shell :在一行开头的符号现在应该是In [1]:在cmd里是>>>
  3. 运行ipython profile create
  4. 进入~/.ipython/profile_default/ipython_config.py并在文本编辑器中打开它,并在末尾添加这两行:

    c.InteractiveShellApp.extensions = ['autoreload']
    c.InteractiveShellApp.exec_lines = ['%autoreload 2']

你现在可以运行python manage.py shell ,编辑你的模型而不必写%autoreload 2