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 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 podem 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) utiliza 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 enviados estão incorretos.

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 flash para informar aos usuários 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 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, cria uma lista global em Python chamada messages, que contém dicionários Python. 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 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, e 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 HTML básico 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 que você referenciou 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 cabeçalho <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 no 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.

Passo 2 — Configurando Formulários

Neste passo, 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 Submit. Quando um usuário preenche o formulário web e clica no botão Submit, 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 template 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 value 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 voltará 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 de título, você adiciona uma área de texto chamada content com o valor {{ request.form['content'] }} pelas mesmas razões mencionadas anteriormente.

Por fim, 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, então 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 Solicitações de Formulário

Neste passo, você lidará com as solicitaçõ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 que criou no passo anterior e os adicionará à lista de mensagens. Você também usará mensagens flash para informar aos usuários quando enviarem dados inválidos. A mensagem flash será mostrada apenas uma vez e desaparecerá na próxima solicitaçã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 os dados de solicitação recebidos que serão enviados através do formulário HTML que você construiu no último passo.
  • A função url_for() para gerar URLs.
  • A função flash() para exibir 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 exibidas 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, permitindo que o Flask lembre 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, você 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-o, 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 subsequente seja executado apenas quando a solicitação for uma solicitação POST através da comparação request.method == 'POST'.

Em seguida, você extrai o título e o conteúdo enviados do objeto request.form, que lhe 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 flash. 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 flash.

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. Você usa a função url_for() para vincular à página inicial.

Salve e feche o arquivo.

Agora, navegue até a rota /create usando 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. Depois de enviar o formulário, você verá a nova mensagem listada na página inicial.

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

  1. nano templates/base.html

Edite o arquivo adicionando uma nova tag `` após o link FlaskApp na barra de navegação dentro da tag `

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 também seriam exibidas na página inicial, pois 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 é obrigató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 requisição anterior. Clicar no link Criar na barra de navegação enviará uma nova requisiçã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 parado, porque listas em Python são apenas salvas na memória. Para salvar suas mensagens permanentemente, você precisará usar um banco de dados como SQLite. Confira Como Usar o Módulo sqlite3 em Python 3 para aprender como usar SQLite com Python.

Conclusão

Você criou uma aplicação Flask onde os usuários podem adicionar mensagens a uma lista de mensagens exibida na página inicial. Você criou um formulário web, tratou os dados que o usuário envia através do 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 você deseja 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