122

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.

Tomasz Wysocki
  • 11,170
  • 6
  • 47
  • 62
Mad Wombat
  • 14,490
  • 14
  • 73
  • 109
  • 2
    You should update this question to mark the "django-extensions" answer correct. – woodardj Nov 16 '13 at 02:39
  • 1
    Not until it actually works for me. I have the extensions installed and none of my code auto-reloads and I don't see any mention of auto-reloading in the shell_plus docs. It seems that there is a reloader in the runserver_plus command, but that is not what I am looking for. – Mad Wombat Dec 02 '15 at 21:17

12 Answers12

124

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.
Paweł BB Drozd
  • 4,483
  • 4
  • 21
  • 17
53

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.

Erik
  • 792
  • 7
  • 10
45

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.

mpaf
  • 6,597
  • 6
  • 38
  • 42
  • 43
    "Just use a python notebook" is not an answer to the OP's question. – J__ Jul 26 '16 at 15:32
  • 1
    This method, while not automatic like %autoreload, does work more reliably than autoreload. kernel restart guarantees that all the cells in the notebook get fully reloaded modules. Plus you can restart and run all cells if you choose. – Anton I. Sipos Mar 01 '17 at 23:01
  • I just get `ModuleNotFoundError: No module named 'notebook.notebookapp'` – Akaisteph7 Aug 10 '23 at 20:18
33

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

dongweiming
  • 811
  • 1
  • 8
  • 8
  • 42
    I use shell_plus and my models are not auto-reloading, am I missing something? – Diego Ponciano Jun 06 '14 at 19:16
  • 38
    shell_plus doesn't reload models, so this does not answer the question. – allanberry Feb 04 '15 at 18:03
  • 5
    as said, shell_plus doesn't reload models. – zenperttu Jul 17 '15 at 09:05
  • I'm using shell_plus right now and my models are reloading as soon as I change the code. I even just changed the definition of a model, and an instance in my shell picked up the change. This should be accepted as the correct answer. – Joseph Sheedy Dec 02 '15 at 19:28
  • 2
    Maybe I am missing something, but shell_plus doesn't reload anything for me. It loads all models at startup, which is convenient, but that is that. – Mad Wombat Dec 02 '15 at 21:13
  • 16
    shell_plus CAN reload modules using the autoreload module. Type '%load_ext autoreload' and then '%autoreload 2' - see https://ipython.org/ipython-doc/3/config/extensions/autoreload.html – bbrame Mar 16 '16 at 14:24
26

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

Mad Wombat
  • 14,490
  • 14
  • 73
  • 109
  • Incorrect. @dongweiming's answer above is the solution, and should be accepted as the best answer. – Joseph Sheedy Dec 02 '15 at 19:25
  • 3
    Multiple comments on his answer say that shell_plus doesn't reload models – Mad Wombat Dec 02 '15 at 21:00
  • 1
    I have just tested it myself and it doesn't reload. Besides, what about non-model code I import by hand? – Mad Wombat Dec 02 '15 at 21:12
  • Classes in an app I'm using now reload great (Python 3.4.3, Django 1.9b1, django-extensions 1.5.9), including a plain non-django-model module and the class within it. It's 5 years since this answer, and a lot of development has happened. – Joseph Sheedy Dec 02 '15 at 21:42
  • 1
    I have tried it on my setup 40 minutes ago and shell_plus doesn't reload anything for me. Django 1.7.10, python 3.4.3, django-extensions 1.5.9. – Mad Wombat Dec 02 '15 at 21:58
  • Good data points. Let's try to figure out the secret combination of things that will help it work for you. Can you try updating Django? – Joseph Sheedy Dec 02 '15 at 22:26
  • No, my project needs 1.7 at the moment. I have checked the docs and nothing anywhere says that shell_plus reloads things. The runserver_plus command does reloads, but not the shell. – Mad Wombat Dec 02 '15 at 22:49
  • Do you have ipython installed? It probably won't work if you're just using the plain python shell. – Joseph Sheedy Dec 02 '15 at 23:03
  • Yes, I have ipython. Version is 4.0.0 – Mad Wombat Dec 02 '15 at 23:17
  • Upgraded to Django 1.8. Same thing, no reloads. – Mad Wombat Dec 15 '15 at 19:15
  • I've been using Django since 1.6 and now I'm using 1.10 (tested all versions between) in none of these versions (always latest django-extensions at the time) it auto reloads. (python 2.6 to 3.5) – Sassan Sep 27 '16 at 18:08
13

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.

andorov
  • 4,197
  • 3
  • 39
  • 52
  • 3
    Thank you for the answer. You might note though, that I asked it in 2010. I am glad to know that after eight years auto-reload finally works in shell_plus :) – Mad Wombat Apr 26 '19 at 16:05
  • I tried this, it didnt work, i also added to `SHELL_PLUS_PRE_IMPORTS` and `SHELL_PLUS_POST_IMPORTS` – Santhosh Mar 08 '21 at 16:58
  • This is very neat – zrbecker Mar 19 '21 at 12:41
  • Still gives warnings: `RuntimeWarning: Model 'xxx.xxxxxx' was already registered. Reloading models is not advised as it can lead to inconsistencies, most notably with related models`. Beware. – Akaisteph7 Aug 10 '23 at 20:46
8

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.

Roque
  • 359
  • 4
  • 8
4

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

Community
  • 1
  • 1
Tomasz Zieliński
  • 16,136
  • 7
  • 59
  • 83
3

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

John J
  • 41
  • 1
  • I love the idea of injecting Rich. However the `code.interact(local=locals())` part does not seem to work with ipython. When I run the same command than you with `shell_plus` rather than `shell`, I still get a normal shell instead of a ipython shell. – David Dahan Aug 31 '22 at 15:01
1

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

Community
  • 1
  • 1
littlegreen
  • 7,290
  • 9
  • 45
  • 51
1

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.

toabi
  • 3,986
  • 1
  • 24
  • 24
0
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
Akshay Vijay Jain
  • 13,461
  • 8
  • 60
  • 73