14 de outubro de 2009

[django] Rodar script da linha de comando

Todo site desenvolvido em Django tem uma configuração básica: o mapeamento de URLs para views, no arquivo urls.py.

E se eu precisar rodar alguma rotina que manipula o banco de dados via linha de comando do terminal? Esse mapeamento não vai me ajudar em nada, porque a rotina que vai rodar a partir do terminal não é uma view que vai mostrar algo usando um template.

Hoje eu me deparei com essa necessidade, pois estou fazendo a carga de dados em algumas tabelas da nova estrutura de um site que estou migrando para Django.

OK, a pergunta inicial seria "por que não usar as fixtures do Django?" (comando manage.py loaddata). Fixtures são boas, mas não para fazer a carga inicial dos dados se eles estiverem numa estrutura diferente da nova. Afinal, criar um arquivo no formato json ou xml é muito chato.

Além disso, eu estaria me preocupando em colocar os dados no formato correto para a fixture funcionar. Mas meu objetivo não era gerar uma fixture. Eu queria os dados carregados na nova estrutura.

Daí a ideia foi:
  1. Ler os dados no formato antigo, em arquivo texto.
  2. Converter e gravar na nova estrutura de tabelas do Django.
  3. Executar um dumpdata para gerar a fixture no formato certo.
Procurando no Google, encontrei uma dica legal do James Bennett, um dos desenvolvedores do Django.

Para fazer o que eu preciso, que é rodar um script python pela linha de comando do terminal, mas usar recursos do ORM do Django, eu preciso seguir os seguintes passos:
  1. Entrar no diretório raiz do meu projeto.
  2. Executar export DJANGO_SETTINGS_MODULE=settings (esse é o pulo do gato)
  3. Executar o script que eu quero a partir do diretório raiz do meu projeto. (esse detalhe é importante!)
Simples assim.

Ao ajustar a variável DJANGO_SETTINGS_MODULE, eu disse ao Django que o arquivo settings.py do meu projeto será usado como configuração do ambiente dele. Como se o site estivesse sendo executado do browser.

Com isso, meu programa pode fazer os imports das classes do model do mesmo jeito que uma view normal faria. Segue abaixo um exemplo simplificado.
#! /usr/bin/env python
from guides.models import Person

def show_men():
for man in Person.objects.filter(gender='male'):
print man.name

Bem, fica aí a dica. Afinal, o terminal é nosso aliado, certo?

Ah... não deixe de visitar a página Colophon do site do James Bennett. Tem coisa interessante ali. ;-)

[Update em 15/10/2009]: não deixe de ler o comentário que o Enrico fez nesse post! A solução dele é muito melhor do que a que eu encontrei.

Eu sou Vinicius Assef, um programador do século passado que gosta de Python, pratica Lean Development e acredita em Deus. Você pode me contactar por email ou twitter.

3 comentários:

  1. Olá Vinicius!
    Na verdade já existe uma maneira mais fácil, você pode criar os seus próprios comandos sem ter que manipular o DJANGO_SETTINGS_MODULE.

    Dá uma olhada aqui:
    http://docs.djangoproject.com/en/dev/howto/custom-management-commands/#howto-custom-management-commands

    Desta forma você tem até algumas facilidades para ler os parâmetros da linha de comando...

    Você falou de migrar um site, vou fazer o meu jabá... Criei uma aplicação para fazer importação de dados no Django, talvez lhe ajude:
    http://code.google.com/p/django-importer/

    Lá tem um projeto de exemplo com um comando neste formato que lhe mostrei.

    Abraço.

    ResponderExcluir
  2. @Enrico, *muito bom!*

    Gostei das 2 dicas: custom management commands e do django-importer também.

    Valeu pela contribuição.

    ResponderExcluir

Marcadores