Flask: Uma Visão Geral
Lançado em 2010, o Flask é um microframework web para Python, criado por Armin Ronacher. Ele se destaca pela sua leveza e flexibilidade, servindo como um núcleo que pode ser estendido com bibliotecas de terceiros para funcionalidades adicionais, como gerenciamento de e-mail (Flask-Mail), autenticação de usuários (Flask-Login) e integração com bancos de dados (Flask-SQLAlchemy). O Flask não impõe um ORM ou um banco de dados específico, permitindo a escolha entre SQL e NoSQL.
Componentes Essenciais: Werkzeug e Jinja2
O funcionamento do Flask é sustentado por duas bibliotecas principais:
- Werkzeug: Um toolkit WSGI (Web Server Gateway Interface) que lida com as tarefas de baixo nível do framework, incluindo roteamento de requisições, manipulação de objetos de requisição e resposta, depuração e o próprio servidor web. O módulo de roteamento (routing) do Werkzeug é responsável por mapear URLs a funções de visualização (view functions) correspondentes. Ele utiliza classes como
Rulepara definir padrões de URL eMappara armazenar essas regras. - Jinja2: Um motor de templates moderno e poderoso que permite a criação de HTML dinâmico. Ele suporta sintaxes para variáveis (
{{ variavel }}), estruturas de controle ({% if condicao %} ... {% else %} ... {% endif %}) e loops ({% for item in lista %} ... {% endfor %}).
Extensões Populares do Flask
A comunidade Flask desenvolveu diversas extensões para facilitar tarefas comuns:
Flask-SQLAlchemy: Para interagir com bancos de dados via ORM.Flask-Script: Para gerenciar tarefas e scripts da aplicação.Flask-Migrate: Para gerenciar migrações de banco de dados.Flask-Session: Para configurar o armazenamento de sessões.Flask-WTF: Para manipulação de formulários web.Flask-Mail: Para envio de e-mails.Flask-Babel: Suporte para internacionalização e localização.Flask-Login: Para autenticação e gerenciamento de estado do usuário.Flask-RESTful: Para desenvolver APIs RESTful.Flask-Bootstrap: Integração com o framework frontend Twitter Bootstrap.Flask-Moment: Formatação e localização de datas e horas.Flask-Admin: Criação de interfaces administrativas.
Configuração do Ambiente Flask
Para iniciar, instale o Flask utilizando o pip:
pip install Flask -i https://pypi.tuna.tsinghua.edu.cn/simple
Exemplo Simples de Flask
Um aplictaivo Flask mínimo envolve a criação de uma instância do aplicativo e a definição de rotas:
from flask import Flask
# Instanciação do objeto Flask
app = Flask(__name__)
# Definição de uma rota e sua função de visualização associada
@app.route("/")
def hello_world():
return "<h1>Olá, Flask!</h1>"
if __name__ == '__main__':
# Execução do servidor de desenvolvimento
# O parâmetro 'debug=True' ativa o modo de depuração, que reinicia o servidor automaticamente após alterações no código.
app.run(debug=True)
Ao executar este script, o Flask iniciará um servidor de desenvolvimento, geralmente acessível em http://127.0.0.1:5000/. Parâmetros como host e port podem ser especificados em app.run() para customizar o endereço e a porta de escuta. O argumento __name__ ajuda o Flask a determinar o caminho raiz do aplicativo para carregar recursos como templates e arquivos estáticos.
Roteamento no Flask
O roteamento é o mecanismo que mapeia URLs para funções específicas em seu aplicativo. Você pode inspecionar as rotas registradas de uma aplicação Flask:
# Supondo que 'app' seja sua instância Flask
print(app.url_map)
# Saída esperada:
# Map([<Rule '/' (HEAD, GET, OPTIONS) -> hello_world>, <Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>])
A decoração @app.route() é usada para associar uma URL a uma função. Ela aceita argumentos opcionais, como methods, para especificar os métodos HTTP permitidos. A função url_for() é útil para gerar URLs dinamicamente com base nos nomes das funções de visualização.
from flask import url_for
# Em algum lugar do seu código, após definir a rota 'hello_world':
# url_para_home = url_for('hello_world') # Gera '/'; se a rota for '/home', geraria '/home'
Funções de Visualização
As funções de visualização (view functions) são o coração da lógica de cada rota. Elas recebem a requisição HTTP, processam os dados necessários e retornam uma resposta. Essa resposta pode ser uma string HTML simples, uma renderização de template, um redirecionamento ou uma resposta JSON.
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
# Renderiza um template HTML chamado 'home.html'
return render_template('home.html')
@app.route("/usuarios/<nome_usuario>")
def perfil_usuario(nome_usuario):
# Processa um parâmetro da URL
return f"Perfil do usuário: {nome_usuario}"
if __name__ == '__main__':
app.run(debug=True)
</nome_usuario>
Templates com Jinja2
O Flask utiliza o Jinja2 por padrão para renderizar templates HTML dinamicamente. A função render_template() carrega e processa esses arquivos.
Sintaxe Jinja2
- Variáveis: Exibidas usando chaves duplas:
{{ nome_variavel }}. - Estruturas de Controle: Usam chaves e porcentagem:
{% if condicao %} ... {% else %} ... {% endif %}. - Loops: Para iterar sobre listas ou sequências:
{% for item in lista %} ... {% endfor %}. - Comentários:
{# Isto é um comentário em Jinja2 #}. - Filtros: Modificam a saída de variáveis (ex:
{{ nome | upper }}para converter para maiúsculas,{{ texto | safe }}para renderizar HTML sem escapar). - Macros: Permitem a criação de funções reutilizáveis dentro dos templates, similares a funções em Python.
- Herança de Templates: Permite que templates estendam outros, definindo blocos substituíveis (
{% block nome_bloco %}...{% endblock %}). - Inclusão de Templates:
{% include 'outro_template.html' %}insere o conteúdo de outro template.
Exemplo Prático de Template
Arquivo templates/exemplo.html:
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<title>Exemplo de Template</title>
</head>
<body>
{# Exemplo de controle de fluxo #}
{% if contador > 5 %}
<p>O contador é maior que 5: {{ contador }}</p>
{% else %}
<p>O contador é 5 ou menor: {{ contador }}</p>
{% endif %}
{# Exemplo de loop #}
{% for i in range(3) %}
<p>Iteração número {{ i + 1 }}</p>
{% endfor %}
{# Exemplo de macro #}
{% macro campo_input(nome, valor='', tipo='text') %}
<input type="{{ tipo }}" name="{{ nome }}" value="{{ valor }}">
{% endmacro %}
{{ campo_input('usuario', 'Exemplo') }}
</body>
</html>
Arquivo app.py:
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/mostrar/<valor>")
def mostrar_exemplo(valor):
nome_dinamico = "Dados dinâmicos"
# Passa variáveis para o template
return render_template('exemplo.html', contador=valor, nome=nome_dinamico)
if __name__ == '__main__':
app.run(debug=True)
</valor>
Gerenciamento de Banco de Dados
O Flask pode ser intgerado com bancos de dados através de bibliotecas como SQLAlchemy.
SQLAlchemy: O ORM
O SQLAlchemy é um mapeador objeto-relacional (ORM) popular para Python.
pip install SQLAlchemy pymysql # Ou outro driver de banco de dados
Tipos e Restrições de Coluna: O SQLAlchemy oferece diversos tipos de dados (Integer, String, Text, DateTime, etc.) e restrições (primary_key, unique, nullable, default, etc.).
Relacionamentos: Suporta relacionamentos um-para-um, um-para-muitos e muitos-para-muitos usando relationship() e ForeignKey().
Operações CRUD com SQLAlchemy
As operações de criação, leitura, atualização e exclusão (CRUD) são realizadas através de uma sessão do SQLAlchemy:
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
# Configuração da conexão com o banco de dados
engine = create_engine('mysql+pymysql://usuario:senha@host/database')
Base = declarative_base()
# Definição de um modelo de tabela
class Usuario(Base):
__tablename__ = 'usuarios'
id = Column(Integer, primary_key=True)
nome = Column(String(50), nullable=False)
# Criação das tabelas no banco de dados (se não existirem)
Base.metadata.create_all(engine)
# Criação de uma sessão
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
session = SessionLocal()
# --- CRUD ---
# Criação (Create)
novo_usuario = Usuario(nome="Alice")
session.add(novo_usuario)
session.commit()
# Leitura (Read)
usuarios = session.query(Usuario).all()
for u in usuarios:
print(u.nome)
# Atualização (Update)
usuario_para_atualizar = session.query(Usuario).filter_by(nome="Alice").first()
if usuario_para_atualizar:
usuario_para_atualizar.nome = "Alice Smith"
session.commit()
# Exclusão (Delete)
usuario_para_excluir = session.query(Usuario).filter_by(nome="Alice Smith").first()
if usuario_para_excluir:
session.delete(usuario_para_excluir)
session.commit()
session.close()
Flask-SQLAlchemy: Integração Simplificada
A extensão Flask-SQLAlchemy simplifica a integração do SQLAlchemy com o Flask.
pip install Flask-SQLAlchemy
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# Configuração da URI do banco de dados
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://usuario:senha@host/database'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Desativa o rastreamento de modificações
db = SQLAlchemy(app)
class Produto(db.Model):
id = db.Column(db.Integer, primary_key=True)
nome = db.Column(db.String(100), nullable=False)
# Criação das tabelas
with app.app_context():
db.create_all()
# Operações CRUD com db.session
novo_produto = Produto(nome="Teclado Gamer")
db.session.add(novo_produto)
db.session.commit()
produtos = Produto.query.all() # Forma mais direta de consultar
for p in produtos:
print(p.nome)
# Acesso à sessão é simplificado com db.session
# db.session.query(...)
# db.session.add(...)
# db.session.commit()
# db.session.delete(...)
Migração de Banco de Dados com Flask-Migrate
O Flask-Migrate (que usa Alembic por baixo dos panos) gerencia as alterações no esquema do banco de dados ao longo do tempo.
pip install Flask-Migrate Flask-Script
# No seu arquivo principal (ex: app.py)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_script import Manager
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///meubanco.db' # Exemplo com SQLite
db = SQLAlchemy(app)
# Modelo de exemplo
class Usuario(db.Model):
id = db.Column(db.Integer, primary_key=True)
nome = db.Column(db.String(50))
migrate = Migrate(app, db)
manager = Manager(app)
# Adiciona o comando 'db' para gerenciar migrações
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
Comandos no terminal:
python seu_script.py db init: Inicializa o diretório de migrações.python seu_script.py db migrate -m "Descrição da migração": Cria um novo script de migração baseado nas mudanças nos modelos.python seu_script.py db upgrade: Aplica as migrações ao banco de dados.python seu_script.py db downgrade: Reverte a última migração.