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

发布于 2024-09-24 08:57:18 字数 328 浏览 5 评论 0原文

我正在使用 Django 并一直使用 Django shell。烦人的部分是,虽然 Django 服务器会在代码更改时重新加载,但 shell 不会,因此每次我对正在测试的方法进行更改时,我都需要退出 shell 并重新启动它,重新导入我的所有模块需要,重新初始化我需要的所有变量等等。虽然 iPython 的历史节省了很多打字时间,但这仍然是一个痛苦。有没有办法让 django shell 自动重新加载,就像 django 开发服务器一样?

我了解 reload(),但我导入了很多模型,并且通常使用 from app.models import * 语法,因此 reload() 没有太大帮助。

I am working with Django and use Django shell all the time. The annoying part is that while the Django server reloads on code changes, the shell does not, so every time I make a change to a method I am testing, I need to quit the shell and restart it, re-import all the modules I need, reinitialize all the variables I need etc. While iPython history saves a lot of typing on this, this is still a pain. Is there a way to make django shell auto-reload, the same way django development server does?

I know about reload(), but I import a lot of models and generally use from app.models import * syntax, so reload() is not much help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

留一抹残留的笑 2024-10-01 08:57:18

我建议使用 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 命令和 3 个自动重新加载策略来阻止某些导入刷新:

%自动重载

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

%自动重载0

  • 禁用自动重新加载。

%自动重载1

  • 每次执行前都会重新加载使用 %aimport 导入的所有模块
    输入的 Python 代码。

%自动重载2

  • 每次都重新加载所有模块(%aimport 排除的模块除外)
    在执行键入的 Python 代码之前。

%aimport

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

%aimport foo

  • 导入模块“foo”并将其标记为自动重新加载 %autoreload 1

%aimport -foo

  • 将模块“foo”标记为不自动重新加载。

这通常适合我的使用,但有一些注意事项:

  • 替换代码对象并不总是成功:将类中的 @property 更改为普通方法或将方法更改为成员变量可能会导致问题(但仅限于旧对象)。
  • 在重新加载模块之前从模块中删除(例如通过猴子修补)的功能不会升级。
  • C 扩展模块无法重新加载,因此无法自动重新加载。

I'd suggest use IPython autoreload extension.

./manage.py shell

In [1]: %load_ext autoreload
In [2]: %autoreload 2

And from now all imported modules would be refreshed before evaluate.

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'

Works also if something was imported before %load_ext autoreload command.

./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'

There is possible also prevent some imports from refreshing with %aimport command and 3 autoreload strategies:

%autoreload

  • Reload all modules (except those excluded by %aimport) automatically
    now.

%autoreload 0

  • Disable automatic reloading.

%autoreload 1

  • Reload all modules imported with %aimport every time before executing
    the Python code typed.

%autoreload 2

  • Reload all modules (except those excluded by %aimport) every time
    before executing the Python code typed.

%aimport

  • List modules which are to be automatically imported or not to be
    imported.

%aimport foo

  • Import module ‘foo’ and mark it to be autoreloaded for %autoreload 1

%aimport -foo

  • Mark module ‘foo’ to not be autoreloaded.

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

  • Replacing code objects does not always succeed: changing a @property in a class to an ordinary method or a method to a member variable can cause problems (but in old objects only).
  • Functions that are removed (eg. via monkey-patching) from a module before it is reloaded are not upgraded.
  • C extension modules cannot be reloaded, and so cannot be autoreloaded.
风筝在阴天搁浅。 2024-10-01 08:57:18

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

python Manage.py shell

测试.py

所以我可以进行更改,保存并再次运行该命令,直到修复我想要修复的任何问题。

My solution to it is I write the code and save to a file and then use:

python manage.py shell < test.py

So I can make the change, save and run that command again till I fix whatever I'm trying to fix.

初见 2024-10-01 08:57:18

我建议使用 django-extensions 项目,如 dongweiming 上面所述。但不只是使用“shell_plus”管理命令,而是使用:

manage.py shell_plus --notebook

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

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

即可,您的代码现在正在使用修改后的模块。

I recommend using the django-extensions project like stated above by dongweiming. But instead of just 'shell_plus' management command, use:

manage.py shell_plus --notebook

This will open a IPython notebook on your web browser. Write your code there in a cell, your imports etc. and run it.

When you change your modules, just click the notebook menu item 'Kernel->Restart'

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

眼眸 2024-10-01 08:57:18

查看django-extensions项目提供的manage.py shell_plus命令。它将在 shell 启动时加载所有模型文件。并自动重新加载您的任何修改但不需要退出,您可以直接在那里调用

look at the manage.py shell_plus command provided by the django-extensions project. It will load all your model files on shell startup. and autoreload your any modify but do not need exit, you can direct call there

满栀 2024-10-01 08:57:18

似乎关于这个主题的普遍共识是 python reload() 很糟糕,并且没有好的方法来做到这一点。

It seems that the general consensus on this topic, is that python reload() sucks and there is no good way to do this.

你穿错了嫁妆 2024-10-01 08:57:18

shell_plus 与 ipython 配置一起使用。这将在 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']

打开 shell - 请注意,您不需要包含 --ipython

python manage.py shell_plus

现在定义任何内容在 SHELL_PLUS_PRE_IMPORTSSHELL_PLUS_POST_IMPORTS (docs) 将自动重新加载!

请注意,如果您的 shell 位于调试器(例如 pdb.set_trace())处,那么当您保存文件时,它可能会干扰重新加载。

Use shell_plus with an ipython config. This will enable autoreload before shell_plus automatically imports anything.

pip install django-extensions
pip install ipython
ipython profile create

Edit your ipython profile (~/.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 (docs) 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.

阳光的暖冬 2024-10-01 08:57:18

针对这种不便,我的解决方案如下。我正在使用 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,必须使用以下方式导入“reload”:

from importlib import reload

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

干杯。

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)

For Python 3.x, 'reload' must be imported using:

from importlib import reload

Hope it helps. Of course it is for debug purposes.

Cheers.

待天淡蓝洁白时 2024-10-01 08:57:18

如果没有一些技巧,Reload() 无法在 Django shell 中工作。您可以具体检查此线程 na 和我的答案:

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

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

How do you reload a Django model module using the interactive interpreter via "manage.py shell"?

等风也等你 2024-10-01 08:57:18

为此,我结合了两个答案,想出了一种简单的单行方法。

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

诀窍是设置您需要的内容,运行 code.interact(local=locals()),然后从您传递的代码中重新启动 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 并说,想要检查表单类,我会得到这个漂亮的输出:
输入图片此处描述

Using a combination of 2 answers for this I came up with a simple one line approach.

You can run the django shell with -c which will run the commands you pass however it quits immediately after the code is run.

The trick is to setup what you need, run code.interact(local=locals()) and then re-start the shell from within the code you pass. Like this:

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

For me I just wanted the rich library's inspect method. Only a few lines:

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

Finally the cherry on top is an alias

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

Now if I startup my shell and say, want to inspect the form class I get this beautiful output:
enter image description here

掐死时间 2024-10-01 08:57:18

不完全是你想要的,但我现在倾向于构建自己的管理命令来测试和摆弄事物。

在命令中,您可以按照您想要的方式设置一堆本地变量,然后放入交互式 shell 中。

import code

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

无需重新加载,而是一种简单且不那么烦人的交互式测试 django 功能的方法。

Not exactly what you want, but I now tend to build myself management commands for testing and fiddling with things.

In the command you can set up a bunch of locals the way you want and afterwards drop into an interactive shell.

import code

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

No reload, but an easy and less annoying way to interactively test django functionality.

玩心态 2024-10-01 08:57:18

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

Instead of running commands from the Django shell, you can set up a management command like so and rerun that each time.

云巢 2024-10-01 08:57:18
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

解决方案使用从 importlib 重新加载,如下

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
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

solution Use reload from importlib as follows

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文