0%
Flask: Criando Aplicações Web Leves em Python

Flask: Criando Aplicações Web Leves em Python

Descubra o Flask para criar aplicações web leves em Python: rotas, templates Jinja2, formulários, APIs JSON, blueprints e deploy em produção.

I

InSkillCoach

· min

Flask: Criando Aplicações Web Leves em Python

Flask é um microframework web para Python: ele fornece o estritamente necessário para construir uma aplicação web (roteamento, templates, tratamento de requisições) e deixa você escolher o resto (banco de dados, autenticação, formulários). Essa filosofia minimalista faz dele um excelente ponto de partida para aprender desenvolvimento web em Python, sem deixar de ser poderoso o bastante para aplicações em produção. Este guia acompanha você da instalação até o deploy.

Instalação e aplicação mínima

Crie um ambiente virtual e depois instale o Flask:

# Création et activation de l'environnement virtuel
python -m venv venv

# Windows
venv\Scripts\activate
# macOS / Linux
source venv/bin/activate

# Installation
pip install flask

Uma aplicação Flask completa cabe em poucas linhas. Crie um arquivo app.py:

from flask import Flask

# Criação da aplicação
app = Flask(__name__)

# Associação de uma URL a uma função (uma "view")
@app.route('/')
def accueil():
    return "Bonjour, Flask !"

if __name__ == '__main__':
    # debug=True : recarregamento automático e mensagens de erro detalhadas
    app.run(debug=True)

Inicie o servidor de desenvolvimento:

python app.py
# * Running on http://127.0.0.1:5000

Abra http://127.0.0.1:5000 no navegador: a página exibe “Bonjour, Flask !”. Nunca use debug=True em produção: o depurador integrado permite executar código arbitrário.

Rotas e métodos HTTP

O decorador @app.route associa uma URL a uma função. Por padrão, uma rota responde apenas a requisições GET; o parâmetro methods autoriza outros verbos HTTP:

from flask import Flask, request

app = Flask(__name__)

@app.route('/contact', methods=['GET', 'POST'])
def contact():
    if request.method == 'POST':
        # Tratamento do envio do formulário
        return "Message reçu"
    # Exibição do formulário (GET)
    return "Formulaire de contact"
MétodoUso típico
GETLer um recurso, exibir uma página
POSTCriar um recurso, enviar um formulário
PUTSubstituir um recurso existente
PATCHModificar parcialmente um recurso
DELETEExcluir um recurso

Parâmetros de URL

Os segmentos variáveis de uma URL são declarados entre sinais de menor e maior e passados como argumento para a função:

# Parâmetro string (padrão)
@app.route('/utilisateur/<nom>')
def profil(nom):
    return f"Profil de {nom}"

# Parâmetro inteiro: /article/42 funciona, /article/abc retorna 404
@app.route('/article/<int:article_id>')
def article(article_id):
    return f"Article numéro {article_id}"

# Parâmetro de caminho: aceita barras
@app.route('/fichiers/<path:chemin>')
def fichier(chemin):
    return f"Chemin demandé : {chemin}"

Conversores disponíveis: string (padrão), int, float, path, uuid.

Os parâmetros de consulta (?tri=date&page=2) são lidos com request.args:

@app.route('/recherche')
def recherche():
    terme = request.args.get('q', '')            # valor padrão: ''
    page = request.args.get('page', 1, type=int)  # conversão automática
    return f"Recherche de « {terme} », page {page}"

Templates Jinja2

Retornar HTML dentro de strings Python rapidamente se torna ilegível. O Flask integra o mecanismo de templates Jinja2: os arquivos HTML ficam em uma pasta templates/.

Estrutura do projeto:

mon_projet/
├── app.py
├── templates/
│   ├── base.html
│   └── index.html
└── static/
    └── style.css

Herança de templates

O template base define a estrutura comum; as páginas preenchem os blocos:

<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <title>{% block titre %}Mon Site{% endblock %}</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <nav>
        <a href="{{ url_for('accueil') }}">Accueil</a>
    </nav>
    <main>
        {% block contenu %}{% endblock %}
    </main>
</body>
</html>
<!-- templates/index.html -->
{% extends "base.html" %}

{% block titre %}Accueil - Mon Site{% endblock %}

{% block contenu %}
<h1>Bienvenue, {{ nom }} !</h1>

{% if articles %}
<ul>
    {% for article in articles %}
    <li>{{ article.titre }} ({{ article.date }})</li>
    {% endfor %}
</ul>
{% else %}
<p>Aucun article pour le moment.</p>
{% endif %}
{% endblock %}

No lado Python, render_template carrega o template e transmite variáveis a ele:

from flask import render_template

@app.route('/')
def accueil():
    articles = [
        {"titre": "Premier article", "date": "2026-09-01"},
        {"titre": "Deuxième article", "date": "2026-09-10"},
    ]
    return render_template('index.html', nom="Alice", articles=articles)

O Jinja2 faz o escape automático do HTML das variáveis, o que protege contra ataques XSS.

Arquivos estáticos

Folhas de estilo, scripts e imagens ficam na pasta static/. A função url_for gera suas URLs:

<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo">

Use sempre url_for em vez de caminhos fixos no código: as URLs continuam corretas mesmo que a aplicação seja implantada sob um prefixo.

Formulários e o objeto request

Os dados de um formulário enviado via POST são lidos com request.form:

from flask import Flask, request, render_template

app = Flask(__name__)

@app.route('/inscription', methods=['GET', 'POST'])
def inscription():
    if request.method == 'POST':
        nom = request.form.get('nom', '').strip()
        email = request.form.get('email', '').strip()

        # Validation minimale
        if not nom or not email:
            return render_template('inscription.html',
                                   erreur="Tous les champs sont obligatoires")

        # Aqui: gravação no banco de dados
        return f"Bienvenue, {nom} !"

    return render_template('inscription.html')
<!-- templates/inscription.html -->
{% extends "base.html" %}
{% block contenu %}
{% if erreur %}<p class="erreur">{{ erreur }}</p>{% endif %}
<form method="post">
    <input type="text" name="nom" placeholder="Votre nom">
    <input type="email" name="email" placeholder="Votre email">
    <button type="submit">S'inscrire</button>
</form>
{% endblock %}

Em projetos reais, a biblioteca Flask-WTF adiciona validação e proteção contra CSRF.

Redirecionamentos e mensagens flash

Após um POST bem-sucedido, redirecione o usuário (padrão “Post/Redirect/Get”) e exiba uma mensagem temporária com flash:

from flask import Flask, flash, redirect, url_for, render_template

app = Flask(__name__)
app.secret_key = "changez-moi-en-production"  # necessário para flash e sessões

@app.route('/enregistrer', methods=['POST'])
def enregistrer():
    # ... tratamento ...
    flash("Enregistrement réussi !", "succes")
    return redirect(url_for('accueil'))
<!-- Dans base.html, avant le bloc contenu -->
{% with messages = get_flashed_messages(with_categories=true) %}
    {% for categorie, message in messages %}
    <div class="flash flash-{{ categorie }}">{{ message }}</div>
    {% endfor %}
{% endwith %}

API JSON com jsonify

O Flask é muito adequado para APIs REST. A função jsonify serializa um dicionário em uma resposta JSON com o cabeçalho Content-Type correto:

from flask import Flask, jsonify, request

app = Flask(__name__)

TACHES = [
    {"id": 1, "titre": "Apprendre Flask", "faite": True},
    {"id": 2, "titre": "Créer une API", "faite": False},
]

@app.route('/api/taches', methods=['GET'])
def lister_taches():
    return jsonify(TACHES)

@app.route('/api/taches/<int:tache_id>', methods=['GET'])
def detail_tache(tache_id):
    tache = next((t for t in TACHES if t["id"] == tache_id), None)
    if tache is None:
        return jsonify({"erreur": "Tâche introuvable"}), 404
    return jsonify(tache)

@app.route('/api/taches', methods=['POST'])
def creer_tache():
    donnees = request.get_json()  # corpo JSON da requisição
    if not donnees or "titre" not in donnees:
        return jsonify({"erreur": "Le champ 'titre' est requis"}), 400
    nouvelle = {"id": len(TACHES) + 1, "titre": donnees["titre"], "faite": False}
    TACHES.append(nouvelle)
    return jsonify(nouvelle), 201

Teste rápido com curl:

curl http://127.0.0.1:5000/api/taches
# [{"faite": true, "id": 1, "titre": "Apprendre Flask"}, ...]

curl -X POST http://127.0.0.1:5000/api/taches \
     -H "Content-Type: application/json" \
     -d '{"titre": "Déployer"}'
# {"faite": false, "id": 3, "titre": "Déployer"}

Estruturando com blueprints

Quando a aplicação cresce, um único arquivo se torna ingerenciável. Os blueprints agrupam as rotas por domínio funcional:

# blog/routes.py
from flask import Blueprint, render_template

blog_bp = Blueprint('blog', __name__, url_prefix='/blog')

@blog_bp.route('/')
def liste_articles():
    return render_template('blog/liste.html')

@blog_bp.route('/<int:article_id>')
def detail(article_id):
    return render_template('blog/detail.html', article_id=article_id)
# app.py
from flask import Flask
from blog.routes import blog_bp

app = Flask(__name__)
app.register_blueprint(blog_bp)
# As rotas /blog/ e /blog/<id> agora estão ativas

Estrutura típica de um projeto organizado:

mon_projet/
├── app.py
├── blog/
│   └── routes.py
├── auth/
│   └── routes.py
├── templates/
└── static/

Configuração e variáveis de ambiente

Nunca coloque segredos (chaves, senhas de banco de dados) no código. Carregue-os a partir do ambiente:

import os
from flask import Flask

app = Flask(__name__)

app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev-uniquement')
app.config['DATABASE_URL'] = os.environ.get('DATABASE_URL')
app.config['DEBUG'] = os.environ.get('FLASK_DEBUG', '0') == '1'

Em desenvolvimento, o pacote python-dotenv carrega automaticamente um arquivo .env (que deve ser excluído do repositório Git via .gitignore):

# .env
SECRET_KEY=une-longue-chaine-aleatoire
DATABASE_URL=postgresql://user:pass@localhost/mabase
FLASK_DEBUG=1

Deploy: gunicorn e nginx

O servidor integrado do Flask é de processo único e não é seguro: ele é reservado ao desenvolvimento. Em produção, use um servidor WSGI como o Gunicorn atrás de um servidor web nginx:

pip install gunicorn

# 4 processos de trabalho, escutando na porta 8000
gunicorn --workers 4 --bind 127.0.0.1:8000 app:app

O nginx atua como proxy reverso: ele recebe o tráfego HTTPS, serve os arquivos estáticos diretamente e encaminha o restante para o Gunicorn:

server {
    listen 80;
    server_name exemple.com;

    location /static/ {
        alias /var/www/mon_projet/static/;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Plataformas como Render, Railway ou Fly.io automatizam essa montagem se você não quiser gerenciar um servidor.

Flask vs Django

CritérioFlaskDjango
FilosofiaMicroframework, minimalistaFramework completo, “baterias incluídas”
Curva de aprendizadoSuave, você aprende conforme a necessidadeMais íngreme, muitos conceitos logo de início
ORMÀ escolha (SQLAlchemy na maioria dos casos)ORM do Django integrado
AdministraçãoA construir ou via extensãoInterface de administração gerada automaticamente
AutenticaçãoExtensão (Flask-Login)Integrada
Estrutura do projetoLivreImposta e convencional
Ideal paraAPIs, microsserviços, sites pequenos, protótiposAplicações completas com back-office

Os dois frameworks são maduros e usados em produção em larga escala. Escolha o Flask pela leveza e flexibilidade, e o Django quando quiser o máximo de funcionalidades prontas para uso.

Boas práticas

  • Use sempre um ambiente virtual e um arquivo requirements.txt (pip freeze > requirements.txt).
  • Desative o modo debug em produção: é uma grave falha de segurança.
  • Gere as URLs com url_for em vez de escrevê-las diretamente no código.
  • Armazene os segredos em variáveis de ambiente, nunca no código-fonte.
  • Estruture com blueprints assim que a aplicação ultrapassar algumas rotas.
  • Retorne os códigos HTTP corretos nas suas APIs: 201 para uma criação, 400 para uma requisição inválida, 404 para um recurso inexistente.
  • Valide todas as entradas do usuário no servidor, mesmo que o formulário já as valide no cliente.

Conclusão

O Flask ilustra perfeitamente a filosofia do Python: simples para começar, extensível para crescer. Agora você sabe criar rotas, gerar páginas com Jinja2, tratar formulários, expor uma API JSON, organizar seu código com blueprints e fazer o deploy com Gunicorn e nginx. O próximo passo natural: conectar um banco de dados com Flask-SQLAlchemy, gerenciar a autenticação com Flask-Login e proteger seus formulários com Flask-WTF.

Para se aprofundar, consulte a documentação oficial do Flask, notavelmente clara e completa.

InSkillCoach

Sobre InSkillCoach

Especialista em treinamento e tecnologias

Coach especializado em tecnologias avançadas e IA, apoiado pela GNeurone Inc.

Certificações:

  • AWS Certified Solutions Architect – Professional
  • Certificações Google Cloud
  • Microsoft Certified: DevOps Engineer Expert
  • Certified Kubernetes Administrator (CKA)
  • CompTIA Security+
1.4k
71

Comentários

Os comentários são alimentados pelo GitHub Discussions

Conecte-se com o GitHub para participar da discussão

Link copiado!