Como Usar Formulários Web em uma Aplicação Flask

O autor selecionou o Free and Open Source Fund para receber uma doação como parte do programa Write for DOnations.

Introdução

Formulários web, como campos de texto e áreas de texto, permitem que os usuários enviem dados para sua aplicação para usá-los para realizar uma ação ou para enviar áreas maiores de texto para a aplicação. Por exemplo, em uma aplicação de mídia social, você pode fornecer aos usuários uma caixa onde possam adicionar novos conteúdos às suas páginas. Outro exemplo é uma página de login, onde você daria ao usuário um campo de texto para inserir seu nome de usuário e um campo de senha para inserir sua senha. O servidor (sua aplicação Flask neste caso) usa os dados enviados pelo usuário e os valida, permitindo o acesso se os dados forem válidos, ou responde com uma mensagem como Credenciais inválidas! para informar ao usuário que os dados que ele enviou não estão corretos.

Flask é um framework web leve em Python que fornece ferramentas e recursos úteis para criar aplicações web na linguagem Python. Neste tutorial, você construirá uma pequena aplicação web que demonstra como usar formulários web. A aplicação terá uma página para exibir mensagens armazenadas em uma lista Python, e uma página para adicionar novas mensagens. Você também usará mensagens de flash para informar aos usuários de um erro quando eles submeterem dados inválidos.

Pré-requisitos

Passo 1 — Exibindo Mensagens

Neste passo, você criará uma aplicação Flask com uma página inicial para exibir mensagens que estão armazenadas em uma lista de dicionários Python.

Primeiro, abra um novo arquivo chamado app.py para edição:

  1. nano app.py

Adicione o seguinte código dentro do arquivo app.py para criar um servidor Flask com uma única rota:

flask_app/app.py
from flask import Flask, render_template

app = Flask(__name__)

messages = [{'title': 'Message One',
             'content': 'Message One Content'},
            {'title': 'Message Two',
             'content': 'Message Two Content'}
            ]

@app.route('/')
def index():
    return render_template('index.html', messages=messages)

Salve e feche o arquivo.

Neste arquivo, você primeiro importa a classe Flask e a função render_template() do pacote flask. Em seguida, usa a classe Flask para criar uma nova instância de aplicação chamada app, passando a variável especial __name__, que é necessária para que o Flask configure alguns caminhos nos bastidores. A renderização de templates é abordada no tutorial Como Usar Templates em uma Aplicação Flask.

Em seguida, você cria uma lista global em Python chamada messages, que contém dicionários Python dentro dela. Cada dicionário possui duas chaves: title para o título da mensagem e content para o conteúdo da mensagem. Este é um exemplo simplificado de um método de armazenamento de dados; em um cenário do mundo real, você usaria um banco de dados que salva os dados permanentemente e permite manipulá-los de forma mais eficiente.

Após criar a lista em Python, você utiliza o decorador @app.route() para criar uma função de visualização chamada index(). Nela, você retorna uma chamada para a função render_template(), que indica ao Flask que a rota deve exibir um modelo HTML. Você nomeia este modelo como index.html (você o criará posteriormente) e passa uma variável chamada messages para ele. Esta variável contém a lista messages que você declarou anteriormente como valor e a torna disponível para o modelo HTML. Funções de visualização são abordadas no tutorial Como Criar Sua Primeira Aplicação Web Usando Flask e Python 3.

Em seguida, crie uma pasta chamada templates no diretório flask_app onde o Flask procura por modelos, então abra um arquivo de modelo chamado base.html, que terá código que outros modelos herdarão para evitar repetição de código:

  1. mkdir templates
  2. nano templates/base.html

Adicione o seguinte código dentro do arquivo base.html para criar o modelo base com uma barra de navegação e um bloco de conteúdo:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .message {
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3
        }
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Salve e feche o arquivo.

Este modelo base contém todo o código boilerplate HTML de que você precisará para reutilizar em seus outros modelos. O bloco title será substituído para definir um título para cada página, e o bloco content será substituído pelo conteúdo de cada página. A barra de navegação possui dois links, um para a página inicial onde você usa a função auxiliar url_for() para vincular à função de visualização index(), e outro para uma página Sobre, caso você opte por incluir uma em sua aplicação.

Em seguida, abra um modelo chamado index.html. Este é o modelo ao qual você fez referência no arquivo app.py:

  1. nano templates/index.html

Adicione o seguinte código a ele:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Messages {% endblock %}</h1>
    {% for message in messages %}
        <div class='message'>
            <h3>{{ message['title'] }}</h3>
            <p>{{ message['content'] }}</p>
        </div>
    {% endfor %}
{% endblock %}

Salve e feche o arquivo.

Neste código, você estende o modelo base.html e substitui o conteúdo do bloco content. Você usa um título <h1> que também serve como título.

Você utiliza um loop for do Jinja na linha {% for message in messages %} para percorrer cada mensagem na lista messages. Você usa uma tag <div> para conter o título e o conteúdo da mensagem. Exibe o título em um cabeçalho <h3> e o conteúdo em uma tag <p>.

Enquanto estiver no diretório flask_app com seu ambiente virtual ativado, informe ao Flask sobre a aplicação (app.py neste caso) usando a variável de ambiente FLASK_APP:

  1. export FLASK_APP=app

Em seguida, defina a variável de ambiente FLASK_ENV como development para executar a aplicação em modo de desenvolvimento e ter acesso ao depurador. Para mais informações sobre o depurador do Flask, consulte Como Manipular Erros em uma Aplicação Flask. Use os seguintes comandos para fazer isso (no Windows, use set em vez de export):

  1. export FLASK_ENV=development

Em seguida, execute a aplicação:

  1. flask run

Com o servidor de desenvolvimento em execução, visite a seguinte URL usando seu navegador:

http://127.0.0.1:5000/

Você verá as mensagens na lista messages exibidas na página inicial:

Agora que você configurou sua aplicação web e exibiu as mensagens, precisará de uma forma de permitir que os usuários adicionem novas mensagens à página inicial. Isso é feito através de formulários web, que você configurará na próxima etapa.

Etapa 2 — Configurando Formulários

Nesta etapa, você criará uma página em sua aplicação que permite aos usuários adicionar novas mensagens à lista de mensagens através de um formulário web.

Deixe o servidor de desenvolvimento em execução e abra uma nova janela de terminal.

Primeiro, abra seu arquivo app.py:

  1. nano app.py

Adicione a seguinte rota ao final do arquivo:

flask_app/app.py
# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    return render_template('create.html')

Salve e feche o arquivo.

Esta rota /create possui o parâmetro methods com a tupla ('GET', 'POST') para aceitar tanto requisições GET quanto POST. GET e POST são métodos HTTP. Por padrão, apenas requisições GET são aceitas, que são usadas para recuperar dados, como solicitar uma página de índice ou uma página Sobre. Requisições POST são usadas para enviar dados a uma rota específica, o que frequentemente altera os dados no servidor.

Neste exemplo, você solicitará a página create usando uma requisição GET. A página Create terá um formulário web com campos de entrada e um botão Enviar. Quando um usuário preenche o formulário web e clica no botão Enviar, uma requisição POST é enviada para a rota /create. Lá, você trata a requisição, valida os dados enviados para garantir que o usuário não tenha enviado um formulário vazio, e adiciona-os à lista messages.

A função de visualização create() atualmente faz apenas uma coisa: renderiza um template chamado create.html quando recebe uma requisição GET regular. Agora você criará este template e, em seguida, editará a função para lidar com requisições POST no próximo passo.

Abra um novo arquivo de template chamado create.html:

  1. nano templates/create.html

Adicione o seguinte código a ele:

flask_app/templates/create.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Add a New Message {% endblock %}</h1>
    <form method="post">
        <label for="title">Title</label>
        <br>
        <input type="text" name="title"
               placeholder="Message title"
               value="{{ request.form['title'] }}"></input>
        <br>

        <label for="content">Message Content</label>
        <br>
        <textarea name="content"
                  placeholder="Message content"
                  rows="15"
                  cols="60"
                  >{{ request.form['content'] }}</textarea>
        <br>
        <button type="submit">Submit</button>
    </form>
{% endblock %}

Salve e feche o arquivo.

Neste código, você estende o modelo base.html e substitui o bloco content com um título <h1> que serve como título da página. No tag <form>, você define o atributo method como post para que os dados do formulário sejam enviados ao servidor como uma requisição POST.

No formulário, você tem um campo de entrada de texto chamado title; este é o nome que você usará na aplicação para acessar os dados do formulário de título. Você dá ao tag <input> um valor de {{ request.form['title'] }}. Isso é útil para restaurar os dados que o usuário insere para que não sejam perdidos quando algo dá errado. Por exemplo, se o usuário esquecer de preencher a área de texto content necessária, uma requisição é enviada ao servidor e uma mensagem de erro será retornada como resposta, mas os dados no título não serão perdidos porque serão salvos no objeto global request e podem ser acessados via request.form['title'].

Após o campo de entrada do título, você adiciona uma área de texto chamada content com o valor {{ request.form['content'] }} pelos mesmos motivos mencionados anteriormente.

Por último, você tem um botão Submit no final do formulário.

Agora, com o servidor de desenvolvimento em execução, use seu navegador para navegar até a rota /create:

http://127.0.0.1:5000/create

Você verá uma página “Adicionar uma Nova Mensagem” com um campo de entrada para o título da mensagem, uma área de texto para o conteúdo da mensagem e um botão Submit.

Este formulário envia uma solicitação POST para a sua função de visualização create(). No entanto, ainda não há código para lidar com uma solicitação POST na função, por isso nada acontece depois de preencher o formulário e enviá-lo. No próximo passo, você lidará com a solicitação POST recebida quando um formulário for enviado. Você verificará se os dados enviados são válidos (não estão vazios) e adicionará o título e o conteúdo da mensagem à lista messages.

Passo 3 — Lidando com Requisições de Formulário

Neste passo, você lidará com requisições de formulário no lado da aplicação. Você acessará os dados do formulário que o usuário envia através do formulário criado no passo anterior e os adicionará à lista de mensagens. Você também usará mensagens flash para informar aos usuários quando enviam dados inválidos. A mensagem flash será mostrada apenas uma vez e desaparecerá na próxima requisição (se você navegar para outra página, por exemplo).

Abra o arquivo app.py para edição:

  1. nano app.py

Primeiro, você importará o seguinte do framework Flask:

  • O objeto global request para acessar dados de requisição recebidos que serão enviados via o formulário HTML construído no último passo.
  • A função url_for() para gerar URLs.
  • A função flash() para enviar uma mensagem quando uma solicitação é processada (para informar ao usuário que tudo correu bem, ou para informá-los sobre um problema se os dados enviados não forem válidos).
  • A função redirect() para redirecionar o cliente para um local diferente.

Adicione essas importações na primeira linha do arquivo:

flask_app/app.py
from flask import Flask, render_template, request, url_for, flash, redirect

# ...

A função flash() armazena mensagens enviadas na sessão do navegador do cliente, o que requer a configuração de uma chave secreta. Esta chave secreta é usada para proteger sessões, que permitem ao Flask lembrar informações de uma solicitação para outra, como passar da página de nova mensagem para a página inicial. O usuário pode acessar as informações armazenadas na sessão, mas não pode modificá-las a menos que tenha a chave secreta, portanto, nunca deve permitir que ninguém acesse sua chave secreta. Consulte a documentação do Flask sobre sessões para mais informações.

A chave secreta deve ser uma string aleatória longa. Você pode gerar uma chave secreta usando o módulo os com o método os.urandom(), que retorna uma string de bytes aleatórios adequada para uso criptográfico. Para obter uma string aleatória usando-a, abra um novo terminal e abra o shell interativo do Python usando o seguinte comando:

  1. python

No shell interativo do Python, importe o módulo os da biblioteca padrão e chame o método os.urandom() da seguinte forma:

  1. import os
  2. os.urandom(24).hex()

Você obterá uma string semelhante à seguinte:

Output
'df0331cefc6c2b9a5d0208a726a5d1c0fd37324feba25506'

Você pode usar a string obtida como sua chave secreta.

Para definir a chave secreta, adicione uma configuração SECRET_KEY ao seu aplicativo através do objeto app.config. Adicione-a diretamente após a definição do app antes de definir a variável messages:

flask_app/app.py

# ...
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'


messages = [{'title': 'Message One',
             'content': 'Message One Content'},
            {'title': 'Message Two',
             'content': 'Message Two Content'}
            ]
# ...

Em seguida, modifique a função de visualização create() para parecer exatamente da seguinte forma:

flask_app/app.py
# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        elif not content:
            flash('Content is required!')
        else:
            messages.append({'title': title, 'content': content})
            return redirect(url_for('index'))

    return render_template('create.html')

Na instrução if, você garante que o código a seguir só é executado quando a solicitação é uma solicitação POST através da comparação request.method == 'POST'.

Em seguida, extraia o título e o conteúdo enviados do objeto request.form, que te dá acesso aos dados do formulário na requisição. Se o título não for fornecido, a condição if not title seria atendida. Nesse caso, você exibe uma mensagem ao usuário informando que o título é obrigatório usando a função flash(). Isso adiciona a mensagem a uma lista de mensagens instantâneas. Posteriormente, você exibirá essas mensagens na página como parte do template base.html. Da mesma forma, se o conteúdo não for fornecido, a condição elif not content será atendida. Se for o caso, você adiciona a mensagem 'Content is required!' à lista de mensagens instantâneas.

Se o título e o conteúdo da mensagem forem enviados corretamente, você usa a linha messages.append({'title': title, 'content': content}) para adicionar um novo dicionário à lista messages, com o título e o conteúdo fornecidos pelo usuário. Então, você usa a função redirect() para redirecionar os usuários para a página inicial. Utiliza a função url_for() para vincular à página inicial.

Salve e feche o arquivo.

Agora, navegue até a rota /create usando o seu navegador web:

http://127.0.0.1:5000/create

Preencha o formulário com um título de sua escolha e algum conteúdo. Após enviar o formulário, você verá a nova mensagem listada na página inicial.

Por fim, você exibirá mensagens instantâneas e adicionará um link para a página “Nova Mensagem” na barra de navegação no template base.html para ter acesso fácil a esta nova página. Abra o arquivo de template base:

  1. nano templates/base.html

Edite o arquivo adicionando uma nova tag `<a>` após o link FlaskApp na barra de navegação dentro da tag `<nav>`. Em seguida, adicione um novo loop `for` diretamente acima do bloco `content` para exibir as mensagens flash abaixo da barra de navegação. Essas mensagens estão disponíveis na função especial `get_flashed_messages()` que o Flask fornece. Em seguida, adicione um atributo de classe chamado `alert` a cada mensagem e forneça algumas propriedades CSS dentro da tag `<style>`:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .message {
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3
        }
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

        .alert {
            padding: 20px;
            margin: 5px;
            color: #970020;
            background-color: #ffd5de;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="{{ url_for('create') }}">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% for message in get_flashed_messages() %}
            <div class="alert">{{ message }}</div>
        {% endfor %}
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Salve e feche o arquivo, e depois recarregue `https://127.0.0.1:5000` no seu navegador. A barra de navegação agora terá um item “Create” que linka para a rota `/create`.

Para ver como as mensagens flash funcionam, vá para a página “Create” e clique no botão Submit sem preencher os dois campos. Você receberá uma mensagem que se parece com isso:

Volte para a página inicial e você verá que as mensagens flash abaixo da barra de navegação desaparecem, mesmo que sejam exibidas como parte do template base. Se não fossem mensagens flash, elas seriam exibidas na página inicial também, porque também herdam do template base.

Tente enviar o formulário com um título, mas sem conteúdo. Você verá a mensagem “Conteúdo é necessário!”. Clique no link FlaskApp na barra de navegação para voltar à página inicial, então clique no botão Voltar para retornar à página de Criação. Você verá que a mensagem de conteúdo ainda está lá. Isso só funciona se você clicar no botão Voltar, porque ele salva a solicitação anterior. Clicar no link Criar na barra de navegação enviará uma nova solicitação, que limpa o formulário, e como resultado, a mensagem flash desaparecerá.

Agora você sabe como receber a entrada do usuário, como validá-la e como adicioná-la a uma fonte de dados.

Nota:
As mensagens que você adiciona à lista messages desaparecerão sempre que o servidor for interrompido, porque listas Python são salvas apenas na memória; para salvar suas mensagens permanentemente, você precisará usar um banco de dados como SQLite. Confira Como Usar o Módulo sqlite3 no Python 3 para aprender a usar SQLite com Python.

Conclusão

Você criou uma aplicação Flask onde os usuários podem adicionar mensagens a uma lista de mensagens exibidas na página inicial. Você criou um formulário web, manipulou os dados que o usuário envia via o formulário e os adicionou à sua lista de mensagens. Você também usou mensagens flash para informar ao usuário quando eles enviam dados inválidos.

Se desejar ler mais sobre Flask, confira os outros tutoriais da série Flask.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-web-forms-in-a-flask-application