Um dos motivos pelos quais o Python é a melhor escolha para o desenvolvimento web é a variedade de estruturas web disponíveis na linguagem. Entre os mais populares e úteis está o Flask, que permite começar de forma simples (“uma gota de cada vez”), mas cresce com seu aplicativo para adicionar praticamente todas as funcionalidades que você precisa.

Neste artigo, veremos como configurar e usar o Flask 3.0 para aplicativos da web básicos. Também abordaremos o uso do Jinja2 para modelagem e como lidar com problemas comuns, como alteração de tipos de resposta e tratamento de redirecionamentos.

Configurando o frasco

O Flask 3.0 é fácil de configurar. Usar pip install flask para instalar o Flask e todas as suas dependências, incluindo o sistema de templates Jinja2.

Como acontece com qualquer estrutura Python, é melhor criar um projeto usando Flask dentro de um ambiente virtual Python. Isso isola seu projeto da instalação principal do Python e de outros projetos que podem usar o Flask e suas dependências (já que você pode manter versões diferentes para projetos diferentes).

Observe que se você deseja instalar o Flask com suporte para funções assíncronas ou corrotinas, use pip install flask(async). Falarei mais sobre como usar o Flask com async em breve.

Um aplicativo Flask básico

Um aplicativo Flask simples e de rota única pode ser escrito em apenas algumas linhas de código. Salve o seguinte exemplo de aplicação simples em um arquivo chamado app.py:


from flask import Flask

app = Flask(__name__)

@app.route("https://www.infoworld.com/")
def home():
    return "Hello, world"

Este aplicativo não faz muita coisa – apenas cria um site com uma única rota que exibe “Olá, mundo” no navegador.

Aqui está o que cada elemento faz:

  • A linha app = Flask(__name__) cria uma nova instância de um aplicativo Flask, chamada app. A classe Flask recebe um argumento que é o nome do módulo ou pacote do aplicativo. Passando __name__ (o nome do módulo atual) é uma maneira rápida de usar o módulo atual como ponto de partida do aplicativo. Em teoria, você pode usar qualquer nome, mas é comum usar o nome do módulo como padrão.
  • O app.route decorador é usado para agrupar uma função e indicar a função a ser usada para entregar uma resposta para uma determinada rota. Neste caso, a rota é a raiz do site ("https://www.infoworld.com/") e a resposta é a string "Hello, world".

Para executar o aplicativo, use python -m flask run no mesmo diretório que app.py. Você deverá ver algo como o seguinte no console:


 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Se você abrir um navegador da web para http://127.0.0.1:5000/você deverá ver as palavras “Olá, mundo”.

Observe que você pode nomear o arquivo principal do seu aplicativo Flask como quiser, mas chamá-lo app.py permite que o Flask o reconheça automaticamente. Para usar um nome diferente, você precisa primeiro definir o FLASK_APP variável de ambiente ao nome do novo arquivo menos sua extensão (por exemplo, hello para hello.py).

Observe também que ao executar um aplicativo Flask dessa maneira, você o executa usando o servidor de teste integrado do Flask, que não é adequado para implantações de produção. Discutiremos como implantar o Flask em produção em breve.

Rotas e variáveis ​​de rota no Flask

Os aplicativos da Web normalmente usam componentes de uma rota como variáveis ​​que são passadas para a função de rota. O Flask permite fazer isso por meio de uma sintaxe especial de definição de rota.

Neste exemplo, onde temos uma rota no formato de /hi/ seguido por um nome de usuário, o nome é extraído e passado para a função como a variável nome de usuário.


@app.route("/hi/<username>")
def greet(username):
    return f"Hello, {username}"

Visite este percurso com /hi/Serdare você verá “Hello, Serdar” no navegador.

Tipos para variáveis ​​de rota Flask

Variáveis ​​de rota também podem ser com restrição de tipoadicionando informações de tipo a eles.

Por exemplo, se você usar <int:userid>que garante userid será apenas um número inteiro. Se você usar <path:datapath>a parte do URL dessa posição em diante será extraída para a variável datapath. Para esse fim, se tivéssemos uma rota como /show/<path:datapath>e usei o URL /show/main/infoentão main/info seria passado na variável datapath. (Consulte a documentação do Flask para obter mais informações sobre variáveis ​​de rota com restrição de tipo.)

Observe que você precisa ter cuidado ao usar vários caminhos semelhantes com diferentes tipos de dados. Se você tem a rota /data/<int:userid> e a rota /data/<string:username>, qualquer elemento na segunda posição que não possa ser correspondido como um número inteiro será correspondido como uma string. Evite esses tipos de estruturas de rotas, se puder, pois elas podem se tornar confusas e difíceis de depurar. Seja o mais inequívoco possível com suas rotas.

Métodos de rota no Flask

Os decoradores de rotas também podem especificar o métodos usado para acessar a rota. Você pode criar múltiplas funções para lidar com uma única rota com métodos diferentes, como este:


@app.route('/post', methods=('GET'))
def post_message_route_get():
    return show_post_message_form()

@app.route('/post', methods=('POST'))
def post_message_route_post():
    return post_message_to_site()

Ou você pode consolidar rotas em uma única função e tomar decisões internamente com base no método:


from flask import request

@app.route('/post', methods=('GET', 'POST'))
def post_message_route():
    if request.method == 'POST':
        return post_message_to_site()
    # defaults to GET if not POST
    return show_post_message_form()

Observe que precisamos importar o global request objeto para acessar a propriedade do método. Exploraremos isso em detalhes mais tarde.

Flask 2.0 e superior também permitem que você use app.get e app.post como atalhos. As rotas acima também podem ser expressas como:


@app.get('/post')
def post_message_route_get():
    return show_post_message_form()

@app.post('/post')
def post_message_route_post():
    return post_message_to_site()

Solicitar dados no Flask

Na última seção, obtivemos o método usado para invocar uma rota do global request objeto. request é uma instância do objeto Request, do qual podemos obter muitos outros detalhes sobre a solicitação – seus cabeçalhos, cookies, dados de formulário, uploads de arquivos e assim por diante.

Algumas das propriedades comuns de um Request objeto incluem:

  • .args: um dicionário que contém os parâmetros de URL. Por exemplo, um URL com argumentos como ?id=1 seria expresso como o dicionário {"id": 1}.
  • .cookies: um dicionário que contém todos os cookies enviados na solicitação.
  • .files: um dicionário que contém todos os arquivos carregados com a solicitação, sendo a chave de cada elemento o nome do arquivo.
  • .form: um dicionário que contém os dados do formulário da solicitação, se houver.
  • .headers: os cabeçalhos brutos da solicitação.
  • .method: O método usado pela solicitação (por exemplo, GET, POST).

Retornando respostas no Flask

Quando uma função de rota retorna dados, o Flask faz a melhor estimativa para interpretar o que foi retornado:

  • Os objetos de resposta são retornados como estão. A criação de um objeto de resposta oferece controle refinado sobre o que você retorna ao cliente, mas para a maioria dos casos de uso você pode usar um dos itens abaixo.
  • Strings, incluindo a saída dos modelos Jinja2 (mais sobre isso a seguir), são convertidas em Response objetos, com um 200 OK código de status e um tipo MIME de text/html.
  • Os dicionários são convertidos em JSON.
  • As tuplas podem ser qualquer uma das seguintes:
    • (resposta, código de status (int))
    • (resposta, cabeçalhos (list/dict))
    • (resposta, código de status (int), cabeçalhos (list/dict))

Geralmente, é melhor retornar o que deixa mais claro o trabalho da função de rota. Por exemplo, um manipulador de erro 404 pode retornar uma tupla de 2 – o código de erro 404 e os detalhes da mensagem de erro. Isso mantém a função de rota organizada.

Modelos no Flask

O Flask inclui o mecanismo de modelo Jinja2 para gerar programaticamente a saída HTML a partir dos dados. Você usa o render_template função para gerar HTML e, em seguida, passar variáveis ​​a serem usadas no modelo.

Aqui está um exemplo de como isso fica em uma rota:


from flask import render_template

@app.route('/hi/<username>')
def greet(username=None):
    return render_template('hello.html', username=username)

Modelos referidos por render_template são encontrados por padrão em um subdiretório do diretório do projeto Flask, denominado templates. Para tanto, o seguinte arquivo estaria em templates/hello.html:


<!doctype html>
<title>Hi there</title>
{% if username %}
  <h1>Hello {{ username }}!</h1>
{% else %}
  <h1>Hello, whoever you are!</h1>
{% endif %}

Os modelos Jinja2 são uma espécie de linguagem, mas este trecho deve lhe dar uma ideia de como eles funcionam. Blocos delineados com {% %} contêm lógica de modelo e blocos com {{ }} contém expressões a serem inseridas nesse ponto. Quando chamamos este modelo com render_template acima, passamos username como argumento de palavra-chave; o mesmo seria feito para quaisquer outras variáveis ​​que usaríamos.

Observe que os modelos Jinja2 têm restrições quanto ao código que pode ser executado dentro deles, por questões de segurança. Portanto, você desejará fazer o máximo de processamento possível para uma determinada página antes passando-o para um modelo.

Manipuladores de erros no Flask

Para criar uma rota que lide com uma classe específica de erro do servidor, use o comando errorhandler decorador:


@app.errorhandler(404)
def page_not_found(error):
    return f"error: {error}"

Para esta aplicação, sempre que for gerado um erro 404, o resultado retornado ao cliente será gerado pelo page_not_found função. O error é a exceção gerada pelo aplicativo, para que você possa extrair mais detalhes dela, se necessário, e repassá-los ao cliente.

Executando e depurando Flask em produção

O servidor de teste Flask mencionado anteriormente neste artigo não é adequado para implantar o Flask em produção. Para implantações de produção, use um servidor totalmente compatível com WSGI, com o app objeto criado por Flask() como o aplicativo WSGI.

A documentação do Flask contém detalhes sobre a implantação nas opções de hospedagem mais comuns, bem como detalhes sobre como hospedar você mesmo aplicativos Flask – por exemplo, por meio do Apache mod_wsgi ou via uWSGI no Nginx.

Usando assíncrono no Flask

Originalmente, o Flask não tinha suporte explícito para funções assíncronas ou corrotinas. As corrotinas agora são um recurso padrão no Python e, a partir da versão 2.0, o Flask oferece suporte a métodos assíncronos para manipuladores de rotas. No entanto, o suporte assíncrono no Flask vem como um complemento, então você precisa usar pip install flask(async) para instalar esse recurso.

Aqui está um exemplo de um frasco async rota:


@app.route("/embed/<embed_id>")
async def get_embed(embed_id):
    data = await async_render_embed(embed_id)
    return data

O suporte assíncrono do Flask não altera o fato de ele ser executado como um aplicativo WSGI com um único trabalhador para lidar com as solicitações recebidas. Se você deseja oferecer suporte a solicitações de longa duração, como conexões de API WebSocket, usar async apenas em suas funções de rota não será suficiente. Você pode considerar o uso da estrutura Quart, que é compatível com API com Flask, mas usa a interface ASGI para lidar melhor com solicitações de longa duração e múltiplas solicitações simultâneas.