GustavoHenrique.net

  • About
  • Contact
  • RSS Feed
  • Twitter

 

22
Dec

Script Python acessando classes do Django

By gustavohenrique|Django|2 Comments


Há uns dias atrás eu precisei criar um relatório com dados obtidos de um BD MySQL usado por um projeto em Django. Esse relatório deveria ser enviado no mesmo horário todos os dias. Sendo assim, criei um script em Python para executar essa tarefa e adicionei uma chamada à ele no Cron (agendador de tarefas do Linux).
A primeira idéia que eu tive foi usar código SQL para obter os dados. Mas aí veio o desânimo: Eu teria que digitar muito. Pensei que se usasse o ORM do Django, em poucas linhas eu conseguiria os dados que preciso. Foi então que decidi usar as classes do Django, montar a estrutura do relatório a partir de um template HTML e enviar por e-mail.

Utilizando as classes do projeto

Vamos supor nesse exemplo que o nome projeto em Django seja meuprojeto, a aplicação minhaapp e o script relatorio.py. Nomes nada criativos, eu sei, mas se você entendeu… é isso que importa.
Então vamos criar o arquivo /usr/bin/relatorio.py contendo as linhas abaixo:

#!/usr/bin/python
from django.core.management import setup_environ
import sys, datetime, settings
PROJECT_PATH = '/home/usuario/www/django/meuprojeto'
sys.path.insert(0, PROJECT_PATH)
setup_environ(settings)

O código acima é tudo que se precisa para usar o projeto dentro do script.
Como exemplo, vamos criar a classe Relatorio, importar a aplicação em Django e instanciar as classes que queremos usar:

# Importamos a classe Cliente
from minhaapp.models import Cliente
 
# Classe para trabalhar com o projeto em Django
class Relatorio(object):
    def teste_exibir_clientes_cadastrados(self):
        clientes = Cliente.objects.all()
        print clientes
 
# Instanciamos a classe Relatorio e executamos o método
rel = Relatorio()
rel.teste_exibir_clientes_cadastrados()

Agora no terminal:

$ sudo chmod +x /usr/bin/relatorio.py
$ relatorio.py

Viram como é fácil trabalhar com o projeto em Django em outro ambiente?!
Agora só falta renderizar um template e enviar o resultado por e-mail.

Renderizando um template

Temos o template relatorio.html localizado no diretório de templates do projeto:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="pt-br">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Relatório de Clientes Cadastrados</title>
</head>
<body>
<h2>Clientes cadastrados</h2>
{% for cliente in clientes %}
    Nome: {{ cliente.nome }}<br />
{% endfor %}
</body>
</html>

Vamos obter os clientes cadastrados, passar o resultado ao template e enviar um e-mail no formato HTML contendo o template renderizado.
O script final deve ficar assim:

#!/usr/bin/python
 
"""Dependendo da distro o caminho para o python acima pode ser outro"""
 
from django.core.management import setup_environ
import sys, datetime, settings
PROJECT_PATH = '/home/gustavo/www/django/meuprojeto'
sys.path.insert(0, PROJECT_PATH)
setup_environ(settings)
 
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
from smtplib import SMTP
import email.Charset
from unicodedata import normalize
 
 
class Relatorio(object):
    def __init__(self):
        """
        Construtor da classe
        """
 
        self.charset = 'utf-8'
        self.smtp_server = 'smtp.provedor.com.br'
        self.smtp_user = 'usuario'
        self.smtp_pass = 'senha'
        self.sender = 'meu@email.com.br'
        self.sender_name = 'Meu Nome Completo'
 
 
    def render(self, context, template):
        """
        Retorna o template renderizado
        """
 
        if template:
            t = loader.get_template(template)
            return t.render(Context(context))
 
 
    def enviar_relatorio(self):
        clientes = Cliente.objects.all()
 
        # Se nao houver clientes cadastrados...
        if not clientes.count() > 0:
            print u'Erro: Nenhum cliente cadastrado. O e-mail não foi enviado.'
        else:
            # Passa os clientes cadastrados para a variavel clientes no template
            context = {'clientes': clientes}
 
            # Obtem o template renderizado
            html = self.render(context, 'relatorio.html')
 
            # A funcao normalize remove caracteres acentuados
            html = normalize('NFKD',html).encode('ASCII','ignore')
 
            # Mais detalhes sobre o módulo email, consulte a docuemtacao do python
            msg_principal = MIMEMultipart('related')
            msg_principal['Subject'] = 'Relatorio de clientes'
            msg_principal['From'] = '%s <%s>' % (self.sender, self.sender_name)
            msg_principal['To'] =  '%s <%s>' % (recipient, recipient_name)
            msg_principal.preamble = 'This is a multi-part message in MIME format.'
 
            msg_alternativa = MIMEMultipart('alternative')
            msg_alternativa.attach(MIMEText(html, 'html', _charset=self.charset))
            msg_principal.attach(msg_alternativa)
            msg_alternativa.attach(MIMEText('Essa e uma mensagem alternativa', _charset=self.charset))
            msg_alternativa.attach(MIMEText(html, 'html', _charset=self.charset))
 
            # Tenta enviar o email
            try:
                smtp = SMTP()
                smtp.connect(self.smtp_server)
                smtp.login(self.smtp_user, self.smtp_pass)
                smtp.sendmail(self.sender, recipient, msg_principal.as_string())
                smtp.quit()
            except:
                print u'Erro: Não foi possível enviar o e-mail.'
 
 
# Instanciamos a classe Relatorio e executamos o método
rel = Relatorio()
rel.enviar_relatorio()

Conclusão

Acessar o ORM do Django por um script Python permite criar muitas coisas interessantes. Imagine criar um projeto no Django e usar suas classes e métodos em um projeto Python + QT por exemplo? E scripts produzindo logs em banco de dados em vez de jogar na tela ou no Syslog, tornando possível a visualização em ambiente web?
A imaginação é o limite.

Bookmark It

Add to Del.icio.us Add to Diigo Add to Facebook Add to Google Bookmarks Add to LinkedIn Add to Mister Wong Add to Twitter Add to Yahoo My Web
Tagged as: python
Add your comment →

2 Comments

  1. Olá!
    Ótimo artigo… mas vai a dica: Não seria mais interessante fazer uma “manager task” para ser executada a partir do comando “python manage.py build_report”, por exemplo?

    By: Klaus Laube Reply →
    December 22, 2009 at 7:39 am
    • A idéia da “manager task” também é interessante e confesso que se quer passou pela minha cabeça. Entretanto, dependendo do tipo de uso e probabilidade de haver implementações no código, poderia ser tornar mais trabalhoso manter como “manager task”.
      Obrigado pela dica!

      By: gustavohenrique Reply →
      December 22, 2009 at 2:37 pm

Leave your comment below! Cancel Reply

View More Posts:
  • ←
  • →

Tags

admin Django extjs firewall grails jquery KingHost liberações Linux manual model modelform mod_wsgi moeda brasileira mudanças mysql nível de serviço oo PagSeguro pdf php PIL pisa problemas proxy python qa qos real relacionamento roteamento service desk shell script sites tdd tipsforlinux traducao ubicomp ubuntu urllib virtualhost Webservices wikipedia xsol __init__

Recent Posts

  • Configurando um servidor LDAP no CentOS 6.2
  • Introdução ao padrão MVC no Ext JS 4
  • Virtualização com KVM
  • Autenticação Facebook no Grails
  • Grails com Sqlite3 no Ubuntu 11.04
  • Deploy no tomcat usando django-jython
  • Deploy múltiplas versões do Django no Nginx com VirtualEnv
  • Comandos básicos do Git
  • Introdução ao Apache Wicket
  • Feliz 2011

Archives

Categories

My tweets

  • @tregismoreira Genesis 7200 com android 4 2 days ago
  • @marcomaciel blz! 1 week ago
  • @marcomaciel hack com qualquer linguagem em qualquer plataforma pra mim ta valendo! #soudev 1 week ago
  • Fui instalar o android 2.3 da lg e agora meu celular não liga. #ffuuu 1 week ago
  • Tentando gerar uma NFe e não consigo =/ #stacktrace Impressionante como todos os sites e apps do governo são ruins. 2 weeks ago
  • More updates...

Powered by the inLine Minimal WordPress Theme