Desenvolvendo uma pequena aplicação web com Python e Flask

Neste artigo será explicado como configurar o seu ambiente de desenvolvimento, desenvolver uma aplicação web em python modularizada e no final publicá-la em um servidor free.

Tópicos abordados:

O que é o Virtualenv?

Virtualenv é um software que permite a criação de ambientes virtuais com total independência dos outros ambientes criados no Virtualenv. Isso permite que cada ambiente tenha autonomia para instalar plug-ins e bibliotecas de forma que a configuração de um ambiente não impacte nos restantes. Um exemplo prático seria a possibilidade de ter várias versões do Python, diferente para cada projeto, instalado na mesma máquina.

 

Instalando o Virtualenv

Para facilitar nossa vida vamos utilizar um módulo Python chamado easy_install que gerencia pacotes Python e possui ferramentas de instalação que realiza automaticamente download, build e instalação dos pacotes disponíveis (no quais são muitos).

sudo easy_install virtualenv

Caso você não tenha o easy_install configurado em sua máquina ainda, execute o seguinte comando no Terminal:

sudo apt-get install python-setuptools python-dev build-essential

A mensagem de sucesso deverá ser algo parecida com a seguinte:

Searching for virtualenv
Best match: virtualenv 1.8.4
Adding virtualenv 1.8.4 to easy-install.pth file
Installing virtualenv script to /usr/local/bin
Installing virtualenv-2.7 script to /usr/local/bin

Using /usr/local/lib/python2.7/dist-packages
Processing dependencies for virtualenv
Finished processing dependencies for virtualenv

Criando o Primeiro Ambiente Virtual

Antes de criar o primeiro ambiente virtual vamos separar um diretório para centralizar todos os documentos, códigos-fontes, configurações e outros assuntos relacionados a Desenvolvimento em um diretório chamado Development na Home do seu usuário no Linux:

cd ~/
mkdir Development

Para manter os ambientes virtuais bem organizados, vamos criar um diretório chamado virtualenvs dentro de Development:

cd ~/Development
mkdir virtualenvs

Agora sim vamos criar nosso primeiro ambiente virtual dentro do diretório virtualenvs. Como mais pra frente nesse post irei explicar como desenvolver uma pequena aplicação, esse ambiente virtual será focado para esse projeto. Então meu ambiente virtual se chamará i-sweated-yesterday:

cd virtualenvs
virtualenv i-sweated-yesterday

A mensagem de sucesso deverá ser algo parecida com a seguinte:

New python executable in i-sweated-yesterday/bin/python
Installing setuptools............done.
Installing pip...............done. 

Caso você desejasse criar um ambiente que não utilize qualquer biblioteca pré instalada no sistema operacional, deveria ser executado da forma a baixo:

virtualenv i-sweated-yesterday --no-site-packages

 

Utilizando o Ambiente Virtual Criado

Ativando

Para utilizar o ambiente virtual você deve ativá-lo antes de realizar qualquer configuração, como instalar ou utilizar alguma biblioteca instalada no mesmo. O comando para ativar o ambiente virtual criado anteriormente é o seguinte:

source i-sweated-yesterday/bin/activate

Sempre que o ambiente virtual estiver ativado irá exibir o nome do ambiente virtual no lado esquerdo das linhas de comando no Terminal (Prompt). No meu caso fica da seguinte forma:

(i-sweated-yesterday)max@Max-Xub-VM:~$

A partir de agora qualquer configuração realizada estará associada apenas ao ambiente virtual ativo no momento.

Desativando

Quando não existir mais a necessidade de utilizar o ambiente virtual no momento, você pode voltar para o ambiente do sistema operacional desativando o ambiente virtual atual:

(i-sweated-yesterday)max@Max-Xub-VM:~$ deactivate 

 

Visualizar os Pacotes Instalados no Ambiente Virtual Atual

Com o ambiente virtual ativado vamos instalar o pacote chamado yolk, que possui a funcionalidade de listar os pacotes já instalados no ambiente atual:

sudo easy_install yolk

Após instalado execute o seguinte comando para visualizar os pacotes instalados:

yolk -l

O que é o Flask?

Flask é um micro framework de desenvolvimento web para Python baseado em duas bibliotecas externas: O Jinja2 e o Werkzeug. Por mais que seja considerado “micro”, Flask suporta extensões de diversas funcionalidades para a sua aplicação, como integração de ORM, validação de formulários, open autenticações e outras diversas extensões.

 

Configurações

Instalando o Flask

Para utilizar o Flask precisamos instalá-lo primeiro (não esqueça de ativar o ambiente virtual antes):

pip install Flask

Vamos aproveitar que estamos instalando o Flask e já vamos instalar alguns outros pacotes para estender as funcionalidades do Flask e deixar o ambiente configurado para nosso aplicativo.

Instalando SQLAlchemy

SQLAlchemy é uma poderosa ferramenta ORM que possibilita aos desenvolvedores trabalhar com dados armazenados no banco de dados de maneira flexível e simplificada.

pip install SQLAlchemy

 

Instalando o Flask-SQLAlchemy

Flask-SQLAlchemy adiciona funcionalidades ao Flask que facilitam algumas tarefas comuns ao utilizar o SQLAlchemy.

pip install flask-sqlalchemy 

 

Instalando o Flask-WTF

Flask-WTF integra de maneira simples o WTForms ao Flask, fornecendo uma maneira fácil de lidar com a apresentação de dados do usuário.

pip install Flask-WTF

Instalando o SQLite3

SQLite é um pacote que disponibiliza um Sistema Gerenciador de Banco de Dados Relacional e permite ser executado através de linha de comando, possibilitando executar qualquer query SQL básica de maneira simples. (Nossa aplicação não dependerá desse pacote para ser executada, mas seria bom já instalá-lo caso surja a necessidade de executar alguma query SQL no banco)

sudo apt-get install sqlite3 libsqlite3-dev

Criando uma Aplicação Flask para Teste

Antes de continuar com a nossa aplicação vamos criar uma aplicação em Flask o mais simples possível, apenas para verificar se o Flask foi instalado corretamente e está funcionando da maneira esperada.

Crie um arquivo chamado hello.py em qualquer diretório dentro de ~/Development:

Os parâmetros debug e port são opcionais mas facilita muito que o debug esteja ativado para visualizar erros que ocorram durante a codificação e utilizando uma porta diferente do padrão 80 possibilita que você rode mais de uma aplicação ao mesmo tempo sem ocorrer o conflito de portas.

Definição do __name__ :

  • Se o módulo é executado diretamente o __name__ é __main__
  • Se o módulo é importado por outro módulo então __name__ é o nome do próprio módulo

Com o virtualenv ativado, rode a linha de comando a baixo e em seguida abra o navegador no endereço “http://localhost:8085 ”:

python hello.py

Caso esteja tudo correto então você deverá visualizar uma página com a mensagem “Hello World”.

Desenvolvendo a Aplicação “I Sweated Yesterday”

I Sweated Yesterday

É uma aplicação pequena e simples para controlar a frequência  de dias que um usuário realiza exercícios físicos. É chamado “Yesterday” porque na empresa em que trabalho, sempre marcamos o exercício físico ao chegarmos na empresa no dia seguinte. Foi baseada na aplicação exemplificada por Armin Ronacher nesta página no Github.

O código fonte da versão dessa aplicação exemplificada nesse post está disponível para download aqui e a versão mais atual está aqui, qual ainda darei mais alguns retoques.

Visão Geral da Estrutura do Projeto

Minha dica aqui é que você crie os arquivos e diretórios abaixo para facilitar quando formos codificar ou faça o download do código fonte a cima.

Diretório Base

Possui arquivos comuns para toda aplicação

/i-sweated-yesterday
/i-sweated-yesterday/initialize-db.py Configurações para inicializar o banco de dados
/i-sweated-yesterday/config.py Variáveis globais da aplicação
/i-sweated-yesterday/app.db Arquivo de banco de dados
/i-sweated-yesterday/run.py Roda a aplica cação
Diretório da Aplicação

Possui o arquivo main, responsável por toda aplicação  

/i-sweated-yesterday/app
/i-sweated-yesterday/app/__init__.py Faz com que o Python trate o diretório como um módulo, realiza a inicialização do Flask, SQLAlchemy e realiza a configuração de rotas básicas
Diretório – Módulo Users

Possui arquivos relacionados ao módulo Users, como formulários, classes modelos (entidade/mapeamento banco), páginas htmls…

/i-sweated-yesterday/app/users
/i-sweated-yesterday/app/users/__init__.py Faz com que o Python trate o diretório como um módulo
/i-sweated-yesterday/app/users/views.py Onde será tratado as requisições (Similar a Controller no MVC)
/i-sweated-yesterday/app/users/forms.py Definição formulários
/i-sweated-yesterday/app/users/constants.py Definição de variáveis Constantes
/i-sweated-yesterday/app/users/models.py Definição de Modelos
/i-sweated-yesterday/app/users/decorators.py Definição de Decorators
/i-sweated-yesterday/app/users/requests.py Definição de Requisições Comuns
Diretório – Módulo Exercises

Possui arquivos relacionados ao módulo Exercises, como formulários, classes modelos (entidade/mapeamento banco), páginas htmls…

/i-sweated-yesterday/app/exercises
/i-sweated-yesterday/app/exercises/__init__.py Faz com que o Python trate o diretório como um módulo
/i-sweated-yesterday/app/exercises/helpers.py Definição de algumas funções uteis
/i-sweated-yesterday/app/exercises/views.py Onde será tratado as requisições (Similar a Controller no MVC)
/i-sweated-yesterday/app/exercises/forms.py Definição formulários
/i-sweated-yesterday/app/exercises/constants.py Definição de variáveis Constantes
/i-sweated-yesterday/app/exercises/models.py Definição de Modelos
Diretório Static

Possui arquivos estáticos como css, imagens  e javascripts

/i-sweated-yesterday/app/static
/i-sweated-yesterday/app/static/css  
/i-sweated-yesterday/app/static/css/reset.css  
/i-sweated-yesterday/app/static/css/main.css  
/i-sweated-yesterday/app/static/js  
/i-sweated-yesterday/app/static/js/main.js  
/i-sweated-yesterday/app/static/img  
Diretório Templates

Possui arquivos de templates, ou seja, todas as páginas htmls puras ou com definições Jinja2

/i-sweated-yesterday/app/templates
/i-sweated-yesterday/app/templates/base.html  
/i-sweated-yesterday/app/templates/users  
/i-sweated-yesterday/app/templates/users/register.html  
/i-sweated-yesterday/app/templates/users/profile.html  
/i-sweated-yesterday/app/templates/users/login.html  
/i-sweated-yesterday/app/templates/forms  
/i-sweated-yesterday/app/templates/forms/macros.html  
/i-sweated-yesterday/app/templates/404.html  
/i-sweated-yesterday/app/templates/exercises  
/i-sweated-yesterday/app/templates/exercises/i_did.html  

Configuração

O arquivo run.py será utilizando durante o desenvolvimento para inicializar a aplicação e disponibilizar o acesso pelo browser no endereço http://localhost:8090:

O arquivo config.py será utilizado para definição de valores comuns de toda aplicação. Mantendo essas informações centralizadas nesse arquivo facilitará durante a publicação para o ambiente de produção ou de testes, que essas informações sejam alteradas de acordo com a necessita de cada ambiente:

_basedir : mantém o caminho de onde os scripts são executados

DEBUG : utilizado como True em ambientes de desenvolvimento, permite que seja exibido detalhadamente a requisição, caso ocorra algum erro durante o processo

SECRET_KEY : utilizado na criação dos cookies

ADMINS : email do Administrador responsável pelo site

SQLALCHEMY_DATABASE_URI e DATABASE_CONNECT_OPTIONS : opções de conexão do SQLAlchemy

CSRF_ENABLED e CSRF_SESSION_KEY : proteção contra fraude de posts

O arquivo initialize-db.py será utilizado para criar a estrutura de tabelas que iremos configurar mais adiante em nossas Models:

Main

O arquivo __init__.py será o main da aplicação, nele estará a definição do Flask, SQLAlchemy e as rotas comuns:

Blueprint basicamente permite que um módulo estenda a aplicação principal e funcione similarmente a aplicação Flask. Sendo esta uma das grandes vantagem para aplicações maiores, por permitir a modularização de uma aplicação, o que facilita em muito a organização, desenvolvimento e manutenções do código fonte.

Veja mais sobre Blueprints.

Módulo Usuário

Como este será um módulo estendido da aplicação principal, o nosso arquivo __init__.py estará vazio, pois objetos que precisamos já foram inicializados pela Main.

O arquivo constants.py é simples e contêm apenas valores Constantes, centralizados todos no mesmo arquivo para priorizar a organização e facilitar caso surja a necessidade de alguma manutenção futura:

O models.py contém a definição da model User, sendo basicamente estruturada pela definições de propriedades, mapeamentos model/database, construtores da classe e métodos GET e SET:

O forms.py  utiliza o módulo WTForms para gerar formulários de maneira fácil e simples, como campos associados a labels e propriedades Required, caso seja obrigatório:

O decorators.py possui a declaração para o decorator requires_login, no qual verifica se o usuário está logado, caso não esteja redireciona o usuário para a página de login:

flask.g : é um objeto no Flask que possui a responsabilidade de armazenar e compartilhar dados através do tempo de execução de uma requisição

*args : o * é utilizado para permitir que um parâmetro aceite um número não definido de argumentos para sua função (parecido com a keyword params no C#)

**kwargs : Da mesma forma, ** permite lidar com argumentos nomeados que não foram previamente definidos (parecido com a keyword params+dictonary no C#)

O requests.py possui a declaração de uma função comum a várias páginas na aplicação. No qual se existir um usuário logado na requisição atual será recuperado o Id do usuário na sessão, então recupera-rá o objeto usuário no banco e será mantido até o final da requisição no objeto flask.g.user:

O views.py, para quem está acostumado com MVC funciona como uma Controller, é onde será definido as requisições possíveis para esse módulo, associando as rotas existentes as funcionalidades específicas de cada uma. Como dito anteriormente esse módulo não será uma aplicação e sim um módulo estendido da aplicação principal. Então ao invés de utilizarmos um objeto do tipo Flask, como para a definição de rotas, iremos utilizar o Blueprint.

validate_on_submit : função do WTForm, no qual verifica se o formulário é valido durante uma requisição do tipo POST ou PUT

render_template : retorna um documento renderizado, no nosso caso todos html, de acordo com o arquivo template e o formulário passado

flash : possibilita que mensagens declaradas na view sejam recuperadas no template e exibidas para o usuário

@mod.route('/login/', methods=['GET', 'POST'])  : associa uma rota a uma função que estiver após sua definição. O primeiro parâmetro define por qual caminho será executado e o segundo parâmetro quais os métodos REST serão aceitos por essa rota.

Templates

Como Flask já possui integrado o Jinja, vamos utilizar em nossos templates algumas de suas funcionalidades disponíveis, como estruturas de condições, laços de repetições, blocos de conteúdos. Permitindo um alto nível de reutilização e fácil desenvolvimento.

O base.html será o template base, do qual será herdado pelos outros templates. Nesse template teremos a definição do corpo HTML, HEAD, BODY e blocos de conteúdo que poderão ser substituídos com outros conteúdos pelos templates que o herdarem.

O macros.html possuirá definições de macros. No nosso caso criamos um macro chamado render_field no qual será responsável por criar uma estrutura HTML para os campos dos nossos formulários. Um detalhe importante desse macro é que caso exista alguma validação que não tenha passado durante a execução do validate_on_submit na view, então as mensagens de erro serão adicionados no HTML gerado.

O register.html herda o base.html e substitui os blocos de conteúdo logout, content e footer. Este template será responsável pelo HTML utilizado no registro de um novo usuário, por isso o método utilizado é o POST e action referencia a url atual sem o nome da página, no qual se verificarmos na view estará apontando para a função register:

A partir de agora será melhor que você siga o resto da aplicação analisando e copiando direto do código fonte disponibilizado mais a cima nesse tutorial, se não este artigo irá ficar muito maior do que já está.

Executando a Aplicação

No primeiro momento que executarmos a aplicação é necessário inicializar o banco de dados, para isso abra o Terminal do sistema operacional, acesse o diretório da aplicação e execute a linha de comando a baixo (não esqueça de antes ativar o ambiente virtual):

python initialize-db.py

Após executado a linha de comando a cima, só a execute novamente caso você deseje resetar o banco de dados, pois será criado as tabelas novamente e perderá todos os dados existentes.

Para inicializar a aplicação execute a linha de comando a baixo:

python run.py

Se a aplicação não possuir nenhuma falha grave será exibido a seguinte mensagem no Terminal:

 * Running on http://127.0.0.1:8090/
 * Restarting with reloader

Para visualizar a aplicação abra qualquer browser com a seguinte URL: http://127.0.0.1:8090/.

O que é o Python Any Where?

O Python Any Where é uma IDE online e serviço de hospedagem baseado em Python. No qual disponibiliza a hospedagem web de aplicações python e acesso ao um console online possibilitando desenvolvimento em python com várias bibliotecas disponíveis de maneira online, fácil e gratuita para o plano mais simples.

Publicando

  1. Crie um cadastro no Python Any Where
  2. Selecione a opção I want to create a web application
  3. Selecione a aba Web e em seguida a opção Add a new web app
  4. Selecione Next na primeira janela
  5. Selecione Flask para definir o Framework Web Python a ser utilizado
  6. Selecione Next para confirmar o caminho físico da sua aplicação
  7. Após criada a opção It is configured via WSGI file stored at para editar arquivo wsgi
  8. Edite o arquivo wsgi, atualizando o valor da variável projec_home com o caminho físico correto da sua aplicação (abra a aba Files para confirmar o caminho correto) e na última linha certifique-se de estar realizando a importação correta, caso você tenha deixado a variável instanciado do Flask no arquivo __init__.py da aplicação como “app”, então você deixará a última linha da forma que está:/ > var > www > YOUR-USER-NAME_pythonanywhere_com_wsgi.py :
  9. Salve o arquivo anterior
  10. Acesse a aba Files e em seguida o diretório : / > home >  YOUR-USER-NAME
  11. Clique no botão Escolher Arquivo
  12. Selecione o seu projeto compactado como .zip
  13. Clique em Upload
  14. Acesse a aba Consoles e selecione a opção Bash
  15. Execute o seguinte comando no console:
    unzip SEU-PROJETO-COMPACTADO.zip 
  16. Para inicializar o banco de dados execute o seguinte comando no console:
    python YOUR-PROJECT-DIRECTORY/initialize-db.py 
  17. Acesse a aba Web e clique em Reload web app
  18. Finalmente para visualizar o aplicativo rodando clique no link You can see your web app at disponível na aba Web (caso ocorra algum erro ao abrir a aplicação, veja a descrição mais detalhada do problema nos logs de erros disponíveis também na aba Web)

Wsgi (Web Server Gateway Interface): Define uma simples interface entre Servidores Web e Aplicações Web ou Frameworks para Python.

Dica : Utilizamos a função de Upload para enviar o código fonte da nossa aplicação do computador local para o servidor web. Mas seria ainda mais fácil quando utilizado o Dropbox ou melhor ainda o Github. De uma olhada nisso, vai facilitar ainda mais o deploy quando realizado várias vezes.