Como recarregar módulos no shell django?

92

Estou trabalhando com Django e uso o shell Django o tempo todo. A parte chata é que enquanto o servidor Django recarrega nas mudanças de código, o shell não, então toda vez que eu faço uma mudança em um método que estou testando, preciso sair do shell e reiniciá-lo, reimportar todos os módulos que preciso, reinicializar todas as variáveis ​​de que preciso etc. Embora o histórico do iPython economize muita digitação nisso, ainda é uma dor. Existe uma maneira de fazer o django shell recarregar automaticamente, da mesma forma que o servidor de desenvolvimento django faz?

Eu sei sobre reload (), mas eu importo muitos modelos e geralmente uso from app.models import *sintaxe, então reload () não ajuda muito.

Mad Wombat
fonte
2
Você deve atualizar esta questão para marcar a resposta "django-extensions" correta.
woodardj
1
Não até que realmente funcione para mim. Eu tenho as extensões instaladas e nenhum de meu código é recarregado automaticamente e não vejo nenhuma menção de recarregamento automático nos documentos shell_plus. Parece que há um recarregador no comando runserver_plus, mas não é isso que estou procurando.
Mad Wombat

Respostas:

38

Eu recomendo usar o projeto django-extensions como afirmado acima por dongweiming. Mas em vez de apenas o comando de gerenciamento 'shell_plus', use:

manage.py shell_plus --notebook

Isso abrirá um notebook IPython em seu navegador da web. Escreva seu código lá em uma célula, suas importações etc. e execute-o.

Quando você mudar seus módulos, apenas clique no item de menu do notebook 'Kernel-> Reiniciar'

Pronto, seu código agora está usando seus módulos modificados.

MPAF
fonte
32
"Basta usar um notebook python" não é uma resposta à pergunta do OP.
J__
1
Este método, embora não seja automático como% autoreload, funciona de forma mais confiável do que autoreload. O reinício do kernel garante que todas as células do notebook sejam totalmente recarregadas. Além disso, você pode reiniciar e executar todas as células, se desejar.
Anton I. Sipos
76

Eu sugiro usar a extensão autoreload IPython .

./manage.py shell

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

E a partir de agora todos os módulos importados seriam atualizados antes de serem avaliados.

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'

Funciona também se algo foi importado antes do %load_ext autoreloadcomando.

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

Também é possível evitar que algumas importações sejam atualizadas com o %aimportcomando e 3 estratégias de autoreload:

% autoreload

  • Recarregue todos os módulos (exceto aqueles excluídos por% aimport) automaticamente agora.

% autoreload 0

  • Desative o recarregamento automático.

% autoreload 1

  • Recarregue todos os módulos importados com% aimport todas as vezes antes de executar o código Python digitado.

% autoreload 2

  • Recarregue todos os módulos (exceto aqueles excluídos por% aimport) todas as vezes antes de executar o código Python digitado.

% aimport

  • Liste os módulos que devem ser importados automaticamente ou não.

% aimport foo

  • Importe o módulo 'foo' e marque-o para ser carregado automaticamente para% autoreload 1

% aimport -foo

  • Marque o módulo 'foo' para não ser carregado automaticamente.

Isso geralmente funciona bem para o meu uso, mas existem algumas cavetas:

  • A substituição de objetos de código nem sempre é bem-sucedida: alterar uma @property em uma classe para um método comum ou um método para uma variável de membro pode causar problemas (mas apenas em objetos antigos).
  • As funções que são removidas (por exemplo, via monkey-patching) de um módulo antes de ser recarregado não são atualizadas.
  • Os módulos de extensão C não podem ser recarregados e, portanto, não podem ser carregados automaticamente.
bodolsog
fonte
3
Caso você esteja usando django's /manage.py shell_plus... se você digitar %load_ext autoreloade então %autoreload 2, os modelos serão automaticamente recarregados.
Fusion
Incrível, você fez meu dia
Shamsul Arefin Sajib
Observe que você precisa do ipython instalado para isso, obviamente. Consulte, por exemplo, stackoverflow.com/a/47170195/50899
Rabarberski
onde colocar este% autoreload? Não fica claro com a resposta
IceFire
40

Minha solução para isso é escrever o código, salvar em um arquivo e usar:

python manage.py shell <test.py

Assim, posso fazer a alteração, salvar e executar esse comando novamente até corrigir o que estou tentando consertar.

Erik
fonte
2
Bom e simples. Uma observação: adicione exit()ao final do arquivo py para sair do shell do Django de maneira mais limpa. THX.
Marc
Solução simples e elegante. Bom trabalho.
nikoskip
38

veja o comando manage.py shell_plus fornecido pelo projeto django-extensions . Ele irá carregar todos os seus arquivos de modelo na inicialização do shell. e autoreload qualquer modificação, mas não precisa sair, você pode chamar direto para lá

Dongweiming
fonte
41
Eu uso shell_plus e meus modelos não estão recarregando automaticamente, estou faltando alguma coisa?
Diego Ponciano
31
shell_plus não recarrega os modelos, portanto, isso não responde à pergunta.
aljabear
5
como disse, o shell_plus não recarrega os modelos.
zenperttu
2
Talvez eu esteja faltando alguma coisa, mas shell_plus não recarrega nada para mim. Ele carrega todos os modelos na inicialização, o que é conveniente, mas é isso.
Mad Wombat
14
shell_plus PODE recarregar módulos usando o módulo autoreload. Digite '% load_ext autoreload' e então '% autoreload 2' - consulte ipython.org/ipython-doc/3/config/extensions/autoreload.html
bbrame
25

Parece que o consenso geral sobre este tópico é que python reload () é uma merda e não há uma boa maneira de fazer isso.

Mad Wombat
fonte
Incorreta. A resposta de @dongweiming acima é a solução e deve ser aceita como a melhor resposta.
Joseph Sheedy
3
Vários comentários em sua resposta dizem que shell_plus não recarrega modelos
Mad Wombat
1
Acabei de testar sozinho e não recarrega. Além disso, o que acontece com o código não modelo que eu importo manualmente?
Mad Wombat
As classes em um aplicativo que estou usando agora são recarregadas muito bem (Python 3.4.3, Django 1.9b1, django-extensions 1.5.9), incluindo um módulo não-modelo django simples e a classe dentro dele. Já se passaram 5 anos desde essa resposta e muito desenvolvimento aconteceu.
Joseph Sheedy
1
Eu tentei em minha configuração 40 minutos atrás e shell_plus não recarrega nada para mim. Django 1.7.10, python 3.4.3, django-extensions 1.5.9.
Mad Wombat
6

Minha solução para esse inconveniente é a seguinte. Estou usando 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)

Para Python 3.x , 'reload' deve ser importado usando:

from importlib import reload

Espero que ajude. Claro que é para fins de depuração.

Felicidades.

Roque
fonte
4

Use shell_plus com uma configuração ipython. Isso será habilitado autoreloadantes que o shell_plus importe qualquer coisa automaticamente.

pip install django-extensions
pip install ipython
ipython profile create

Edite seu perfil ipython ( ~/.ipython/profile_default/ipython_config.py):

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

Abra um shell - observe que você não precisa incluir --ipython:

python manage.py shell_plus

Agora, qualquer coisa definida em SHELL_PLUS_PRE_IMPORTSou SHELL_PLUS_POST_IMPORTS( docs ) será carregada automaticamente!

Observe que se seu shell estiver em um depurador (ex pdb.set_trace()), quando você salvar um arquivo, ele pode interferir no recarregamento.

andorov
fonte
2
Obrigado pela resposta. Você pode notar, porém, que eu perguntei em 2010. Fico feliz em saber que após oito anos de auto-reload finalmente funciona em shell_plus :)
Mad Wombat
1

Em vez de executar comandos no shell do Django, você pode configurar um comando de gerenciamento como este e executá- lo novamente a cada vez.

littlegreen
fonte
1

Usando uma combinação de 2 respostas para isso, eu vim com uma abordagem simples de uma linha.

Você pode executar o shell django com -c que irá executar os comandos que você passar, no entanto, ele fecha imediatamente após a execução do código.

O truque é configurar o que você precisa, execute code.interact (local = locals ()) e reinicie o shell de dentro do código que você passou. Como isso:

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

Para mim, eu só queria o método de inspeção da rica biblioteca. Apenas algumas linhas:

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

Finalmente, a cereja do bolo é um pseudônimo

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

Agora, se eu iniciar meu shell e disser, quero inspecionar a classe de formulário, recebo esta bela saída: insira a descrição da imagem aqui

John J
fonte
0

Não é exatamente o que você quer, mas agora tenho a tendência de construir comandos de gerenciamento para testar e mexer nas coisas.

No comando, você pode configurar vários locais da maneira que quiser e depois colocá-los em um shell interativo.

import code

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

Sem recarregar, mas uma maneira fácil e menos irritante de testar interativamente a funcionalidade do django.

toabi
fonte