Extensão autoreload no IPython para recarregar models do Django

Postado em 24 de Fevereiro de 2018 às 21:42


Sou desenvolvedor Python/Django e muitas e muitas vezes utilizo o comando:

./manage.py shell

Para os iniciantes que não conhecem este comando, ele abre um interpretador Python, na versão configurada em seu ambiente de desenvolvimento, para que você possa testar e acessar os módulos do seu projeto. Geralmente é utilizado para testar as QuerySets, formulários, etc

Eu lembro que uma das maiores frustrações como iniciante era ter que ficar reiniciando o shell para atualizar os models quando eu realizava alguma migração. Mas um belo dia pesquisei por uma solução e "para nossa alegria" encontrei uma extensão do IPython supimpa para meu problema. Trata-se da "autoreload". Sugestivo não? Claro que para utiliza-la você precisa ter o IPython instalado em seu ambiente de desenvolvimento Python. Depois de acessar o shell (com o comando acima, ./manage.py shell) você carrega a extensão como no exemplo abaixo:

%load_ext autoreload
%autoreload 2

Com esse comando, todos os módulos que você importou serão recarregados (é o que indica o argumento "2" na frente da extensão autoreload) todas as vezes antes de executar um código digitado no interpretador, e assim você não precisa se preocupar com as alterações que for realizando durante o desenvolvimento. Vamos ver uma situação simples, imagine o model Orcamento do app orcamentos (orcamentos.models.Orcamento):

class Orcamento(models.Model):
    descricao = models.CharField(max_length=255)
    valor = models.DecimalField(max_digits=10, decimal_places=2)

    def __str__(self):
        return self.descricao

    class Meta:
        verbose_name = "Orçamento"
        verbose_name_plural = "Orçamentos"
   

Vamos supor que após criar o model, você deseja entrar no shell interativo (./manage.py shell) e salvar alguns objetos:

from orcamentos.models import Orcamento

orcamento = Orcamento()
orcamento.descricao = "Criar uma loja virtual"
orcamento.valor = 15000.00
orcamento.save()

Beleza, o orçamento foi salvo. Mas ai você foi lá e alterou o model Orcamento adicionando um campo novo chamado "cliente":

class Orcamento(models.Model):
    descricao = models.CharField(max_length=255)
    valor = models.DecimalField(max_digits=10, decimal_places=2)
    cliente = models.CharField(max_length=255)

    def __str__(self):
        return self.descricao

    class Meta:
        verbose_name = "Orçamento"
        verbose_name_plural = "Orçamentos"

Após realizar as migrações necessárias, se você voltar ao mesmo terminal que cadastrou o orçamento acima, você não vai conseguir cadastrar o cliente e provavelmente vai receber uma exceção como esta:

IntegrityError: NOT NULL constraint failed: orcamentos_orcamento.cliente

Você precisa fechar este shell interativo e abrir outro para que o model seja atualizado, ou seja, digitar novamente o comando "./manage.py shell", e ai o model atualizado será carregado. Agora sim é possível cadastrar o cliente do orçamento:

from orcamentos.models import Orcamento

    orcamento = Orcamento()
    orcamento.descricao = "Criar outra loja virtual"
    orcamento.valor = 15000.00
    orcamento.cliente = "Lojas Fulano"
    orcamento.save()

Repare que você precisou fazer novamente o import do model Orcamento. Sacou o drama? Nas primeiras 4 vezes tudo bem, mas imagina um projeto com dezenas de models, fica inviável ficar reabrindo o shell. Ai que entram o IPython e a extensão autoreload. A primeira coisa a se fazer é instalar o IPython no seu ambienete de desenvolvimento com o comando:

pip install ipython

Com o IPython instalado é só entrar no shell (./manage.py shell) e importar a extensão autoreload:

Python 3.6.3 (default, Oct  3 2017, 21:45:48) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: %load_ext autoreload

In [2]: autoreload 2

A partir dai, todos os módulos importados serão recarregados automagicamente. SUCESSO! Eu usei como exemplo os models do django, mas esta extensão funciona com qualquer módulo que for carregado, seja um projeto django ou outro projeto qualquer.

Saiba mais:

Documentação Django: https://docs.djangoproject.com/pt-br/2.0/

Documentação IPython: http://ipython.readthedocs.io/en/stable/index.html

Documentação Extensão Autoreload: http://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html