如何在 django shell 中重新加载模块?

我正在使用 Django,并且一直在使用 Django shell。令人恼火的是,当 Django 服务器重新加载代码更改时,shell 却不会,所以每次我对正在测试的方法进行更改时,我都需要退出 shell 并重新启动它,重新导入所有我需要的模块,重新初始化所有我需要的变量等等。虽然 iPython 历史记录节省了大量的输入,但这仍然是一个痛苦的问题。是否有一种方法可以使 django shell 自动重载,就像 django 开发服务器所做的那样?

我知道 reload () ,但是我导入了很多模型,并且通常使用 from app.models import *语法,所以 reload ()没有多大帮助。

55795 次浏览

Reload() doesn't work in Django shell without some tricks. You can check this thread na and my answer specifically:

如何使用交互式解释器通过“ manage.py shell”重新加载 Django 模型模块?

似乎在这个主题上的普遍共识是,python reload ()糟透了,而且没有好的方法可以做到这一点。

查看由 姜戈接发项目提供的 manage.py shell _ plus 命令。它将在 shell 启动时加载所有的模型文件。并且自动重载您的任何修改,但不需要退出,您可以直接呼叫那里

您可以设置一个管理命令 像这样并每次重新运行它,而不是从 Django shell 运行命令。

我建议使用 django 扩展项目,就像上面东伟明提到的那样,但是不要仅仅使用“ shell _ plus”管理命令,而是使用:

manage.py shell_plus --notebook

这将在您的 Web 浏览器上打开一个 IPython 笔记本。在单元格中编写代码,导入代码等并运行它。

更改模块时,只需单击笔记本菜单项“内核-> 重新启动”

There you go, your code is now using your modified modules.

不完全是你想要的,但我现在倾向于为自己建立测试和摆弄东西的管理命令。

在这个命令中,您可以按照自己的方式设置一些局部变量,然后将其放入一个交互式 shell 中。

import code


class Command(BaseCommand):
def handle(self, *args, **kwargs):
foo = 'bar'
code.interact(local=locals())

没有重新加载,但是一个交互式测试 django 功能的简单且不那么烦人的方法。

我的解决方案是编写代码并保存到一个文件中,然后使用:

Python management. py shell < test.py

因此,我可以进行更改,保存并再次运行该命令,直到修复要修复的内容。

My solution for this inconvenient follows. I am using IPython.

$ ./manage.py shell
> import myapp.models as mdls   # 'mdls' or whatever you want, but short...
> mdls.SomeModel.objects.get(pk=100)
> # At this point save some changes in the model
> reload(mdls)
> mdls.SomeModel.objects.get(pk=100)

对于 Python 3. x,必须使用以下方法导入“重新加载”:

from importlib import reload

希望有帮助。当然是为了调试的目的。

干杯。

我建议使用 IPython autoreload extension

./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命令和3种自动重载策略防止一些导入刷新:

% autoreload

  • 自动重新加载所有模块(% aimport 排除的模块除外) 现在。

% autoreload 0

  • Disable automatic reloading.

% autoreload 1

  • 每次执行前用% aimport 重新加载所有导入的模块 类型化的 Python 代码。

% autoreload 2

  • 每次重新加载所有模块(% aimport 排除的模块除外) before executing the Python code typed.

% aimport

  • 列出要自动导入或不要导入的模块 进口的。

% aimport foo

  • 导入模块“ foo”并将其标记为% autoreload 1的 autoreload

% aimport-foo

  • 标记模块‘ foo’不能自动重载。

This generally works good for my use, but there are some cavetas:

  • 替换代码对象并不总是成功: 将类中的@属性更改为普通方法或将方法更改为成员变量可能会导致问题(但仅限于旧对象)。
  • 在重新加载模块之前从模块中删除(例如通过修补程序)的函数不会升级。
  • C extension modules cannot be reloaded, and so cannot be autoreloaded.

使用带有 ipython 配置的 shell_plus。这将在 shell _ plus 自动导入任何内容之前启用 autoreload

pip install django-extensions
pip install ipython
ipython profile create

编辑您的 ipython 配置文件(~/.ipython/profile_default/ipython_config.py) :

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

Open a shell - note that you do not need to include --ipython:

python manage.py shell_plus

Now anything defined in SHELL_PLUS_PRE_IMPORTS or SHELL_PLUS_POST_IMPORTS (医生) will autoreload!

Note that if your shell is at a debugger (ex pdb.set_trace()) when you save a file it can interfere with the reload.

使用这两个答案的组合,我想出了一个简单的单行方法。

您可以使用-c 运行 django shell,它将运行您传递的命令,但是在代码运行后立即运行 退出

诀窍是设置您需要的内容,运行 code.Interactive (local = local ()) ,然后从您传递的代码中重新启动 shell。像这样:

python manage.py shell -c 'import uuid;test="mytestvar";import code;code.interact(local=locals())'

对我来说,我只想要富有的图书馆的检查方法。只有几行:

python manage.py shell -c 'import code;from rich import pretty;pretty.install();from rich import inspect;code.interact(local=locals())'

最后,上面的樱桃是个化名

alias djshell='python manage.py shell -c "import code;from rich import pretty;pretty.install();from rich import inspect;code.interact(local=locals())"'

现在,如果我启动我的 shell,然后说,想要检查表单类,我得到了这个漂亮的输出: enter image description here

import test  // test only has x defined
test.x       // prints 3, now add y = 4 in test.py
test.y       // error, test does not have attribute y

按照下面的方式从 import lib 重新加载

from importlib import reload
import test // test only has x defined
test.x // prints 3, now add y = 4 in test.py
test.y // error
reload(test)
test.y // prints 4