Programador Leigo
Flask 9 min leitura 10 MAR 2026

Rotas e formulários: páginas que recebem dados

Capture dados da URL e de formulários HTML para criar páginas interativas.


Rotas dinâmicas no Flask

Uma das funcionalidades mais úteis do Flask é a possibilidade de criar rotas dinâmicas. Em vez de definir uma URL fixa para cada página, você captura partes da URL como variáveis e usa esses valores dentro da função.

A sintaxe é simples: basta colocar o nome da variável entre < e > na rota.

from flask import Flask

app = Flask(__name__)

@app.route("/usuario/<nome>")
def perfil(nome):
    return f"Bem-vindo, {nome}!"

Ao acessar /usuario/maria, a variável nome recebe o valor "maria" e a página exibe a saudação correspondente.

Conversores de tipo

Por padrão, toda variável capturada na URL chega como string. Mas o Flask oferece conversores que validam e convertem o tipo automaticamente. Se o valor não bater com o tipo esperado, o Flask retorna um erro 404.

@app.route("/produto/<int:id>")
def produto(id):
    return f"Produto de ID: {id}"

@app.route("/arquivo/<path:caminho>")
def arquivo(caminho):
    return f"Caminho solicitado: {caminho}"

Os conversores disponíveis são:

  • string — aceita qualquer texto sem barra (padrão)
  • int — aceita números inteiros
  • float — aceita números decimais
  • path — como string, mas aceita barras
  • uuid — aceita strings no formato UUID

Você pode combinar mais de uma variável na mesma rota sem problema:

@app.route("/loja/<string:categoria>/<int:pagina>")
def listar(categoria, pagina):
    return f"Categoria: {categoria} | Pagina: {pagina}"

Gerando URLs com url_for()

Escrever URLs manualmente no código é arriscado: se você mudar a rota, precisa atualizar todos os lugares onde ela aparece. O url_for() resolve isso gerando a URL a partir do nome da função.

from flask import Flask, url_for

app = Flask(__name__)

@app.route("/")
def inicio():
    link = url_for("perfil", nome="joao")
    return f'<a href="{link}">Ver perfil do Joao</a>'

@app.route("/usuario/<nome>")
def perfil(nome):
    return f"Perfil de {nome}"

As vantagens são claras: se a rota /usuario/<nome> mudar para /u/<nome>, o url_for() continua funcionando sem precisar alterar o restante do código. Além disso, ele cuida automaticamente da codificação de caracteres especiais na URL.

O objeto request

Para acessar dados enviados pelo navegador, o Flask disponibiliza o objeto request. Ele contém informações sobre a requisição atual: parâmetros da URL, dados de formulários, método HTTP e muito mais.

from flask import Flask, request

app = Flask(__name__)

@app.route("/busca")
def busca():
    termo = request.args.get("q", "")
    pagina = request.args.get("pagina", 1, type=int)
    return f"Buscando por: {termo} | Pagina: {pagina}"

Ao acessar /busca?q=flask&pagina=2, o request.args captura os parâmetros da query string. O método .get() aceita um valor padrão e até um tipo para conversão automática.

Os atributos mais usados do request são:

  • request.args — parâmetros da query string (GET)
  • request.form — dados enviados por formulário (POST)
  • request.method — método HTTP da requisição (GET, POST, etc.)
  • request.files — arquivos enviados via upload

Formulários HTML com POST

Para enviar dados ao servidor, o caminho mais comum é criar um formulário HTML que usa o método POST. No Flask, a mesma rota pode aceitar GET e POST usando o parâmetro methods.

from flask import Flask, request, render_template_string

app = Flask(__name__)

FORMULARIO = """
<form method="POST" action="/login">
    <input type="text" name="email" placeholder="E-mail">
    <input type="password" name="senha" placeholder="Senha">
    <button type="submit">Entrar</button>
</form>
"""

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        email = request.form.get("email")
        senha = request.form.get("senha")
        return f"Login recebido: {email}"
    return FORMULARIO

Quando o usuário acessa /login pelo navegador, o método é GET e o formulário é exibido. Quando ele preenche e clica em "Entrar", o navegador envia os dados via POST e a mesma função trata o envio.

Validação básica no servidor

Nunca confie apenas na validação do lado do cliente. O servidor precisa verificar se os dados recebidos estão corretos antes de processá-los.

@app.route("/cadastro", methods=["GET", "POST"])
def cadastro():
    erros = []
    if request.method == "POST":
        nome = request.form.get("nome", "").strip()
        email = request.form.get("email", "").strip()

        if not nome:
            erros.append("O nome e obrigatorio.")
        if not email or "@" not in email:
            erros.append("Informe um e-mail valido.")

        if not erros:
            # salvar no banco de dados
            return "Cadastro realizado com sucesso!"

    return render_template_string("""
        {% for erro in erros %}
            <p style="color:red">{{ erro }}</p>
        {% endfor %}
        <form method="POST">
            <input name="nome" placeholder="Nome">
            <input name="email" placeholder="E-mail">
            <button>Cadastrar</button>
        </form>
    """, erros=erros)

A validação acontece inteiramente no servidor. Os erros são coletados em uma lista e exibidos acima do formulário para que o usuário corrija os campos.

Flash messages para feedback

O Flask possui um sistema embutido de mensagens temporárias chamado flash messages. Elas são perfeitas para exibir avisos como "Cadastro realizado!" ou "Erro ao salvar" após um redirecionamento.

from flask import Flask, flash, get_flashed_messages, redirect, url_for, request

app = Flask(__name__)
app.secret_key = "chave-secreta"

@app.route("/salvar", methods=["POST"])
def salvar():
    nome = request.form.get("nome", "").strip()
    if not nome:
        flash("O campo nome nao pode ficar vazio.", "erro")
    else:
        flash("Dados salvos com sucesso!", "sucesso")
    return redirect(url_for("formulario"))

@app.route("/formulario")
def formulario():
    mensagens = get_flashed_messages(with_categories=True)
    html = ""
    for categoria, msg in mensagens:
        cor = "green" if categoria == "sucesso" else "red"
        html += f'<p style="color:{cor}">{msg}</p>'
    html += """
        <form method="POST" action="/salvar">
            <input name="nome" placeholder="Seu nome">
            <button>Salvar</button>
        </form>
    """
    return html

As flash messages ficam armazenadas na sessão do usuário e são consumidas automaticamente na próxima requisição. Isso significa que, ao recarregar a página, a mensagem desaparece.

Redirect após POST (padrão PRG)

O padrão Post/Redirect/Get (PRG) resolve um problema clássico: quando o usuário atualiza a página após um envio de formulário, o navegador reenvia os dados. Isso pode causar duplicações indesejadas.

A solução é simples: após processar o POST, redirecione o usuário para uma rota GET.

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

app = Flask(__name__)
app.secret_key = "chave-secreta"

@app.route("/contato", methods=["GET", "POST"])
def contato():
    if request.method == "POST":
        # processa os dados
        flash("Mensagem enviada!")
        return redirect(url_for("contato"))
    # exibe o formulario no GET
    return "<form method='POST'><button>Enviar</button></form>"

Após o redirect, o navegador faz uma nova requisição GET. Se o usuário apertar F5, apenas o GET é repetido — sem reenvio do formulário.

Exemplo prático: formulário de contato

Vamos juntar tudo em um exemplo completo: um formulário de contato com validação no servidor, flash messages e o padrão PRG.

from flask import (
    Flask, request, redirect, url_for,
    flash, get_flashed_messages, render_template_string,
)

app = Flask(__name__)
app.secret_key = "minha-chave-secreta"

TEMPLATE_CONTATO = """
<!DOCTYPE html>
<html>
<head><title>Contato</title></head>
<body>
    <h1>Fale conosco</h1>
    {% for cat, msg in get_flashed_messages(with_categories=true) %}
        <p style="color:{{ 'green' if cat == 'sucesso' else 'red' }}">
            {{ msg }}
        </p>
    {% endfor %}
    <form method="POST" action="{{ url_for('contato') }}">
        <label>Nome:</label><br>
        <input type="text" name="nome"><br><br>
        <label>E-mail:</label><br>
        <input type="email" name="email"><br><br>
        <label>Mensagem:</label><br>
        <textarea name="mensagem" rows="5" cols="40"></textarea><br><br>
        <button type="submit">Enviar</button>
    </form>
</body>
</html>
"""

@app.route("/contato", methods=["GET", "POST"])
def contato():
    if request.method == "POST":
        nome = request.form.get("nome", "").strip()
        email = request.form.get("email", "").strip()
        mensagem = request.form.get("mensagem", "").strip()

        if not nome:
            flash("Preencha o campo nome.", "erro")
        if not email or "@" not in email:
            flash("Informe um e-mail valido.", "erro")
        if not mensagem:
            flash("A mensagem nao pode ficar vazia.", "erro")

        erros = get_flashed_messages()
        if not erros:
            # aqui voce enviaria o e-mail ou salvaria no banco
            flash("Mensagem enviada com sucesso!", "sucesso")
            return redirect(url_for("contato"))

    return render_template_string(TEMPLATE_CONTATO)

if __name__ == "__main__":
    app.run(debug=True)

O fluxo completo funciona assim: o usuário acessa /contato via GET e vê o formulário. Ao submeter, o servidor valida os campos. Se houver erros, o formulário é reexibido com as mensagens em vermelho. Se tudo estiver correto, uma flash message de sucesso é criada e o usuário é redirecionado para a mesma rota via GET — aplicando o padrão PRG.

Com essas ferramentas — rotas dinâmicas, url_for(), o objeto request, validação, flash messages e o padrão PRG — você já consegue construir páginas interativas completas no Flask.

Continue lendo

Compartilhar