O autor selecionou o Free and Open Source Fund para receber uma doação como parte do programa Write for DOnations.
O Flask é framework Web pequeno e leve para o Pyhton, que fornece ferramentas e recursos úteis que facilitam a criação de aplicativos Web em Python. Ele dá flexibilidade aos desenvolvedores e é um framework mais acessível para novos desenvolvedores, pois é possível desenvolver um aplicativo Web rapidamente usando apenas um único arquivo Python. O Flask é extensível e não força uma estrutura de diretório em específico. Ele também não exige códigos boilerplate complicados antes de iniciar.
Como parte deste tutorial, você usará o Kit de ferramentas de inicialização para estilizar seu aplicativo torná-lo visualmente mais atrativo. A inicialização ajudará você a incorporar páginas Web dinâmicas em seu aplicativo Web para que ele funcione bem em navegadores de celulares, sem a necessidade de escrever códigos em HTML, CSS e JavaScript para atingir esses objetivos. O kit de ferramentas permitirá que você se concentre na aprendizagem de como o Flask funciona.
O Flask utiliza o mecanismo de modelo Jinja para desenvolver dinamicamente páginas HTML utilizando conceitos do Python conhecidos, como variáveis, loops, listas e assim por diante. Você utilizará esses modelos como parte deste projeto.
Neste tutorial, você desenvolverá um pequeno blog na Web usando o Flask e o SQLite em Python 3. Os usuários do aplicativo podem visualizar todas as postagens em seu banco de dados e clicar no título de uma postagem para visualizar seu conteúdo. Eles também podem adicionar novas postagens ao banco de dados e editar ou excluir uma postagem existente.
Antes de começar a seguir este guia, você precisará do seguinte:
flask_blog
.Neste passo, você ativará seu ambiente Python e instalará o Flask usando o instalador de pacotes pip
.
Caso ainda não tenha ativado seu ambiente de programação, confirme que você está em seu diretório do projeto (flask_blog
) e use o comando a seguir para ativar o ambiente:
- source env/bin/activate
Assim que seu ambiente de programação for ativado, seu prompt terá um prefixo env
que pode parecer-se com o seguinte:
-
Este prefixo é um indicativo que o ambiente env
está ativo. O ambiente pode ter outro nome, dependendo da maneira como você o chamou durante sua criação.
Nota: você pode usar o Git, um sistema de controle de versão, para gerenciar e rastrear o processo de desenvolvimento do seu projeto de maneira eficaz Para aprender como usar o Git, verifique nosso artigo de Introdução à instalação do Git: uso e ramificações.
Caso esteja usando o Git, é recomendável ignorar o diretório env
recém-criado em seu arquivo .gitignore
para evitar o rastreamento de arquivos não relacionados ao projeto.
Agora, você instalará pacotes do Python e isolará seu código do projeto da instalação principal do sistema Python. Você fará isso usando o pip
e python
.
Para instalar o Flask, execute o seguinte comando:
- pip install flask
Assim que a instalação for concluída, execute o seguinte comando para confirmá-la:
- python -c "import flask; print(flask.__version__)"
Utilize a interface de linha de comando python
com a opção -c
para executar o código Python. Em seguida, importe o pacote flask
com o comando import flask;
em seguida imprima na tela a versão do Flask, que é fornecida através da variável flask.__version__
.
A saída será um número da versão parecido com este:
Output1.1.2
Você criou a pasta do projeto, um ambiente virtual e instalou o Flask. Agora, você está pronto para seguir para a configuração do seu aplicativo base.
Agora que você tem seu ambiente de programação configurado, você começará a usar o Flask. Neste passo, você criará um aplicativo Web pequeno dentro de um arquivo Python e o executará para iniciar o servidor, que mostrará informações no navegador.
Em seu diretório flask_blog
, abra um arquivo chamado hello.py
para editá-lo. Use o nano
ou seu editor de texto favorito:
- nano hello.py
Este arquivo hello.py
servirá como um exemplo mínimo de como processar solicitações HTTP. Dentro dele, você importará o objeto Flask
e criará uma função que retorna uma resposta HTTP. Escreva o seguinte código dentro do hello.py
:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
No bloco de código anterior, importe o objeto Flask
do pacote flask
. Em seguida, use-o para criar sua instância de aplicativo Flask com o nome app
. Passe a variável especial __name__
que guarda o nome do módulo Python atual. Ela é usada para dizer à instância onde ela está localizada. Isso é necessário, pois o Flask configura alguns caminhos sem que você veja.
Assim que criar a instância app
, use-a para processar solicitações Web de entrada e enviar respostas ao usuário. O @app.route
é um decorador que transforma uma função Python comum em uma função de visualização Flask. Ela converte o valor de retorno da função em uma resposta HTTP para ser mostrada por um cliente HTTP, como um navegador Web. Passe o valor '/'
para @app.route()
para indicar que esta função responderá às solicitações Web para a URL /
, que é a URL principal.
A função de visualização hello()
retorna a string 'Hello, World!'
como resposta.
Salve e feche o arquivo.
Para executar seu aplicativo Web, diga primeiro ao Flask onde encontrar o aplicativo (o arquivo helly.py
no seu caso) com a variável de ambiente FLASK_APP
:
- export FLASK_APP=hello
Em seguida, execute-o em modo de desenvolvimento com a variável de ambiente FLASK_ENV
:
- export FLASK_ENV=development
Por último, execute o aplicativo utilizando o comando flask run
:
- flask run
Assim que o aplicativo estiver em execução, o resultado será algo parecido com isto:
Output * Serving Flask app "hello" (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 813-894-335
O resultado anterior tem várias informações, como:
Debug mode: on
mostra que o depurador Flask está funcionando. Isso é bastante útil no processo de desenvolvimento, pois nos envia mensagens de erro detalhadas quando as coisas dão errado, facilitando assim, a resolução de problemas.http://127.0.0.1:5000/
, 127.0.0.1
é o IP que representa o localhost
de sua máquina e :5000
é o número da porta.Abra um navegador e digite na URL http://127.0.0.1:5000/
. Você receberá a string Hello, World!
como uma resposta. Isso confirma que seu aplicativo está funcionando corretamente.
Aviso: O Flask utiliza um servidor Web simples para exibir nosso aplicativo em um ambiente de desenvolvimento. Isso também significa que o depurador do Flask está funcionando para facilitar a captura de erros. O servidor de desenvolvimento não deve ser utilizado em uma implantação de produção. Consulte a página de opções de implantação na documentação do Flask para obter maiores informações. Você também pode consultar este tutorial de implantação do Flask.
Agora, deixe o servidor de desenvolvimento em execução no terminal e abra outra janela do terminal. Vá para a pasta do projeto onde o hello.py
está localizado, ative o ambiente virtual, defina as variáveis do ambiente FLASK_ENV
e FLASK_APP
e prossiga para os passo seguintes. (Estes comandos estão listados anteriormente neste passo.)
Nota: ao abrir um novo terminal, é importante lembrar de ativar o ambiente virtual e a configurar as variáveis de ambiente FLASK_ENV
e FLASK_APP
.
Embora o servidor de desenvolvimento do aplicativo Flask já esteja funcionando, não é possível executar outro aplicativo Flask com o mesmo comando flask run
. Isso acontece porque o flask run
usa a porta de número 5000
por padrão, e uma vez ocupada, ela se torna indisponível para execução de outro aplicativo. Dessa forma, você receberia um erro parecido com este:
OutputOSError: [Errno 98] Address already in use
Para resolver este problema, pare o servidor que está em execução no momento através do CTRL+C
e execute o flask run
novamente. Ou caso queira executar os dois ao mesmo tempo, passe um número de porta diferente para o argumento -p
. Por exemplo, para executar outro aplicativo na porta 5001
, use o seguinte comando:
- flask run -p 5001
Agora, você tem um aplicativo Web Flask pequeno. Você executou seu aplicativo e exibiu informações no navegador Web. Em seguida, você usará arquivos HTML em seu aplicativo.
No momento, seu aplicativo mostra somente uma mensagem simples sem HTML. Os aplicativos Web usam, em sua maioria, o HTML para exibir informações para os visitantes. Desta forma, você trabalhará na incorporação de arquivos HTML em seu aplicativo, que podem ser exibidos no navegador Web.
O Flask fornece uma função auxiliar render_template()
que permite o uso do mecanismo modelo do Jinja. Isso facilitará bastante o gerenciamento do HTML ao escrever seu código HTML em arquivos .html
e ao usar lógica em seu código HTML. Você usará esses arquivos HTML, (modelos) para desenvolver todas as suas páginas do aplicativo, como a página inicial onde você exibirá as postagens do blog, a página da postagem do blog, a página onde o usuário pode adicionar postagens e assim por diante.
Neste passo, você criará seu aplicativo Flask em um novo arquivo.
Primeiro, em seu diretório flask_blog
, use o nano
ou seu editor de texto favorito para criar e editar seu arquivo app.py
. Esse arquivo terá todo o código que você utilizará para criar o aplicativo do blog:
- nano app.py
Neste novo arquivo, você importará o objeto Flask
para criar uma instância do aplicativo Flask, como fez anteriormente. Você também importará a função auxiliar render_template()
, que permite que você renderize seus arquivos modelo do HTML na pasta templates
que você está prestes a criar. O arquivo terá uma única função de visualização, que será responsável por processar as solicitações para a rota /
principal. Adicione o conteúdo a seguir:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
A função de visualização index()
retorna o resultado da chamada render_template()
com o index.html
como um argumento. Isso informa o render_template()
para procurar um arquivo chamado index.html
na templates folder. Tanto a pasta quanto o arquivo não existem ainda. Você receberá um erro se executar o aplicativo neste ponto. Apesar disso, você o executará para se familiarizar com essa exceção encontrada. Em seguida, você o consertará criando a pasta e o arquivo necessários.
Salve e saia do arquivo.
Pare o servidor de desenvolvimento em seu outro terminal que está executando o aplicativo hello
com o CTRL+C
.
Antes de executar o aplicativo, especifique corretamente o valor para a variável de ambiente FLASK_APP
, pois você já não está usando o aplicativo hello
:
- export FLASK_APP=app
- flask run
Abrir a URL http://127.0.0.1:5000/
em seu navegador mostrará a página de depuração informando que o modelo index.html
não foi encontrado. A linha principal no código que foi responsável por este erro estará destacada. Neste caso, é a linha return render_template('index.html')
.
Se você clicar nesta linha, o depurador revelará mais do código para você ter um contexto maior e assim ajudá-lo a resolver o problema.
Para corrigir este erro, crie um diretório chamado templates
dentro do seu diretório flask_blog
. Em seguida, abra um arquivo chamado index.html
para poder editá-lo:
- mkdir templates
- nano templates/index.html
Depois disso, adicione o seguinte código HTML dentro de index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FlaskBlog</title>
</head>
<body>
<h1>Welcome to FlaskBlog</h1>
</body>
</html>
Salve o arquivo e use seu navegador para acessar o endereço http://127.0.0.1:5000/
novamente, ou atualize a página. Desta vez, o navegador deve mostrar o texto Welcome to FlaskBlog
em uma tag <h1>
.
Além da pasta templates
, os aplicativos Web normalmente possuem uma pasta static
para arquivos estáticos de hospedagem, como arquivos CSS, arquivos JavaScript e imagens que o aplicativo utiliza.
Você pode criar uma folha de estilos style.css
para adicionar o CSS ao seu aplicativo. Primeiro, crie um diretório chamado static
dentro de seu diretório flask_blog
principal:
- mkdir static
Em seguida crie outro diretório chamado css
dentro do diretório static
para hospedar os arquivos .css
. Normalmente, isso é feito para organizar arquivos estáticos em pastas dedicadas, pois esses arquivos JavaScript estão dentro de um diretório chamado js
. As imagens são colocadas em um diretório chamado images
(ou img
), etc. O comando a seguir criará o diretório css
dentro do diretório static
:
- mkdir static/css
Após isso, abra um arquivo style.css
dentro do diretório css
para editá-lo:
- nano static/css/style.css
Adicione a seguinte regra CSS ao seu arquivo style.css
:
h1 {
border: 2px #eee solid;
color: brown;
text-align: center;
padding: 10px;
}
O código CSS adicionará uma borda, alterará a cor para marrom, centralizará o texto e adicionará um pouco de preenchimento para as tags <h1>
.
Salve e feche o arquivo.
Em seguida, abra o arquivo de modelo index.html
para editá-lo:
- nano templates/index.html
Você adicionará um link ao arquivo style.css
dentro da seção <head>
do arquivo de modelo index.html
:
. . .
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="{{ url_for('static', filename= 'css/style.css') }}">
<title>FlaskBlog</title>
</head>
. . .
Aqui, utilize a função auxiliar url_for()
para gerar a localização apropriada do arquivo. O primeiro argumento especifica que você está se vinculando a um arquivo estático e o segundo argumento é o caminho do arquivo dentro do diretório estático.
Salve e feche o arquivo.
Após atualizar a página inicial do seu aplicativo, você notará que o texto Welcome to FlaskBlog
está marrom, centralizado e fechado dentro de uma borda.
Você pode usar a linguagem CSS para estilizar o aplicativo e torná-lo mais atraente usando sua criatividade. No entanto, se você não for um Web designer, ou não estiver familiarizado com o CSS, pode utilizar o kit de ferramentas do Bootstrap, que fornece componentes fáceis de usar para estilizar seu aplicativo. Neste projeto, utilizaremos o Bootstrap.
Você deve ter imaginado que criar outro modelo HTML significaria repetir a maior parte do código HTML que você já escreveu no modelo index.html
. É possível evitar repetições desnecessárias do código com a ajuda de um arquivo de modelo base, a partir do qual serão herdados todos os seus arquivos HTML. Consulte a Herança de modelo em Jinja para obter maiores informações.
Para criar um modelo base, crie primeiro um arquivo chamado base.html
dentro de seu diretório templates
:
- nano templates/base.html
Digite o seguinte código em seu modelo base.html
:
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>{% block title %} {% endblock %}</title>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-light bg-light">
<a class="navbar-brand" href="{{ url_for('index')}}">FlaskBlog</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="#">About</a>
</li>
</ul>
</div>
</nav>
<div class="container">
{% block content %} {% endblock %}
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
Salve e feche o arquivo assim que terminar de editá-lo.
A maior parte do código no bloco anterior trata-se de padrões de HTML e código necessários para o Bootstrap. As tags <meta>
fornecem informações para o navegador Web, a tag <link>
vincula os arquivos CSS do Bootstrap e as tags <script>
são links para o código JavaScript que permitem algumas funcionalidades adicionais do Bootstrap. Confira a documentação do Bootstrap para obter maiores informações.
No entanto, as partes destacadas são específicas para o mecanismo modelo do Jinja:
{% block title %} {% endblock %}
: um bloco que serve como espaço reservado para um título; você o utilizará mais tarde em outros modelos para fornecer um título personalizado para cada página em seu aplicativo, sem reescrever a seção <head>
inteira toda vez.{{ url_for('index')}}
: uma chamada de função que retornará a URL para a função de visualização index()
. Essa é diferente da chamada url_for()
anterior que você utilizou para vincular um arquivo CSS estático, pois ela recebe apenas um argumento, ou seja, o nome da função de visualização e os links para a rota associada com a função, em vez de um arquivo estático.{% block content %} {% endblock %}
: outro bloco que será substituído pelo conteúdo, dependendo do modelo filho (modelos podem herdar do arquivo base.html
) que o substituirá.Agora que você tem um modelo base, tire proveito dele usando a herança. Abra o arquivo index.html
:
- nano templates/index.html
Depois, substitua o conteúdo dele com o seguinte:
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% endblock %}
Nesta nova versão do modelo index.html
, utilize a tag {% extends %}
para herdar do modelo base.html
. Em seguida, estenda-o substituindo o bloco content
no modelo base pelo o que está dentro do bloco content
no bloco de código anterior.
Esse bloco content
contém uma tag <h1>
com o texto Welcome to FlaskBlog
dentro de um bloco title
, que substitui o bloco title
original no modelo base.html
pelo texto Welcome to FlaskBlog
. Dessa maneira, é possível evitar repetir o mesmo texto duas vezes, pois ele funciona tanto como um título para a página quanto um cabeçalho que aparece abaixo da barra de navegação herdada do modelo base.
A herança do modelo também dá a você a capacidade de reutilizar o código HTML que você tem em outros modelos (base.html
neste caso), sem precisar repeti-lo sempre que ele é necessário.
Salve e feche o arquivo e atualize a página inicial no seu navegador. Você verá sua página com uma barra de navegação e um título estilizado.
Você utilizou os modelos HTML e os arquivos estáticos em Flask. Você também usou o Bootstrap para iniciar o refinamento do visual de sua página e um modelo base para evitar repetições de código. No próximo passo, você configurará um banco de dados que armazenará os dados do seu aplicativo.
Neste passo, você configurará um banco de dados para armazenar dados, ou seja, as postagens do blog do seu aplicativo. Você também preencherá o banco de dados com alguns exemplos de entrada.
Você utilizará um arquivo SQLite database para armazenar seus dados, pois o módulo sqlite3
(que utilizaremos para interagir com o banco de dados), está disponível na biblioteca padrão do Python. Para obter maiores informações sobre o SQLite, confira este tutorial.
Como os dados no SQLite são armazenados em tabelas e colunas e seus dados são constituídos principalmente de postagens de blogs, você precisa criar uma tabela chamada posts
com as colunas necessárias. Você criará um arquivo .sql
que contém comandos SQL para criar a tabela posts
com algumas colunas. Em seguida, você utilizará esse arquivo para criar o banco de dados.
Abra um arquivo chamado schema.sql
dentro de seu diretório flask_blog
:
- nano schema.sql
Digite os comandos SQL seguintes dentro deste arquivo:
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
title TEXT NOT NULL,
content TEXT NOT NULL
);
Salve e feche o arquivo.
O primeiro comando SQL é o DROP TABLE IF EXISTS posts;
. Ele exclui qualquer tabela já existente chamada posts
para evitar um comportamento confuso. Note que sempre que usar esses comando SQL eles excluirão todo o conteúdo que você tem no banco de dados. Por este motivo, não escreva qualquer conteúdo importante no aplicativo Web até terminar este tutorial e testar o resultado final. O comando CREATE TABLE posts
é utilizado para criar a tabela posts
com as seguintes colunas:
id
: um número inteiro que representa uma chave primária; ele receberá um valor único pelo banco de dados para cada entrada (ou seja, uma postagem do blog).created
: a hora que a postagem foi criada no blog. NOT NULL
significa que esta coluna não deve estar vazia e o valor DEFAULT
é o valor CURRENT_TIMESTAMP
, que é o horário que a postagem foi adicionada ao banco de dados. Assim como o id
, não é necessário que você especifique um valor para esta coluna, pois ela será preenchida automaticamente.title
: o título da postagem.content
: o conteúdo da postagem.Agora que você possui um esquema SQL no arquivo schema.sql
, você o utilizará para criar o banco de dados usando um arquivo Python que gerará um arquivo de banco de dados .db
. Abra um arquivo chamado init_db.py
dentro do diretório flask_blog
usando seu editor de texto preferido:
- nano init_db.py
Depois disso, adicione o código seguinte.
import sqlite3
connection = sqlite3.connect('database.db')
with open('schema.sql') as f:
connection.executescript(f.read())
cur = connection.cursor()
cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
('First Post', 'Content for the first post')
)
cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
('Second Post', 'Content for the second post')
)
connection.commit()
connection.close()
Você importará o módulo sqlite3
e abrirá uma conexão a um arquivo de banco de dados chamado database.db
, que você criará assim que executar o arquivo Python. Em seguida, use a função open()
para abrir o arquivo schema.sql
. Agora, execute seu conteúdo usando o método executescript()
, que executa várias instruções SQL de uma só vez que criarão a tabela posts
. Crie um objeto de cursor que permita que você utilize o método execute()
dele para executar duas instruções SQL INSERT
para adicionar duas postagens do blog em sua tabela posts
. Por fim, confirme as alterações e feche a conexão.
Salve e feche o arquivo e, depois, execute-o no terminal usando o comando python
:
- python init_db.py
Assim que o arquivo terminar a execução, um novo arquivo chamado database.db
aparecerá em seu diretório flask_blog
. Isso significa que você configurou seu banco de dados com sucesso.
No próximo passo, você recuperará as postagens que inseriu em seu banco de dados e as mostrará na página inicial do seu aplicativo.
Agora que configurou o banco de dados, você pode modificar a função de visualização index()
para exibir todas as postagens em seu banco de dados.
Abra o arquivo app.py
para fazer as seguintes modificações:
- nano app.py
Para sua primeira modificação, você importará o módulo sqlite3
na parte superior do arquivo:
import sqlite3
from flask import Flask, render_template
. . .
Em seguida, crie uma função que cria uma conexão de banco de dados e a retorna. Adicione-a diretamente após as importações:
. . .
from flask import Flask, render_template
def get_db_connection():
conn = sqlite3.connect('database.db')
conn.row_factory = sqlite3.Row
return conn
. . .
A função get_db_connection()
abre uma conexão ao arquivo de banco de dados database.db
e, em seguida, define o atributo row_factory
ao sqlite3
.Row para que você tenha acesso baseado em nome às colunas. Ou seja, a conexão do banco de dados retornará linhas que se comportam como um dicionário comum do Python. Por último, a função retorna o objeto de conexão conn
que você utilizará para acessar o banco de dados.
Após definir a função get_db_connection()
, modifique a função index()
para ela se parecer com a seguinte:
. . .
@app.route('/')
def index():
conn = get_db_connection()
posts = conn.execute('SELECT * FROM posts').fetchall()
conn.close()
return render_template('index.html', posts=posts)
Nesta nova versão da função index()
, abra primeiro uma conexão de banco de dados usando a função get_db_connection()
definida anteriormente. Em seguida, execute uma consulta SQL para selecionar todas as entradas da tabela posts
. Implemente o método fetchall()
para obter todas as linhas do resultado da consulta. Isso retornará uma lista das postagens que você inseriu no banco de dados no passo anterior.
Feche a conexão do banco de dados usando o método close()
e retorne o resultado da renderização do modelo index.html
. Passe o objeto posts
como um argumento que contém os resultados obtidos do banco de dados. Isso permitirá seu acesso às postagens do blog no modelo index.html
.
Com essas modificações feitas, salve e feche o arquivo app.py
.
Agora que você passou as postagens que obteve do banco de dados ao modelo index.html
, utilize um loop for
para exibir cada uma de suas postagens na página inicial.
Abra o arquivo index.html
:
- nano templates/index.html
Em seguida, modifique-o para se parecer com o que segue:
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% for post in posts %}
<a href="#">
<h2>{{ post['title'] }}</h2>
</a>
<span class="badge badge-primary">{{ post['created'] }}</span>
<hr>
{% endfor %}
{% endblock %}
Aqui, a sintaxe {% for post in posts %}
é um loop for
do Jinja, que é parecido com o loop for
do Python, exceto que ele precisa ser fechado depois com a sintaxe {% endfor %}
. Use essa sintaxe para fazer um loop em toda a lista posts
que foi passada pela função index()
na linha return render_template('index.html', posts=posts)
. Dentro deste loop for
você mostra o título da postagem em um cabeçalho <h2>
dentro de uma tag <a>
(você usará esta tag mais tarde para vincular cada postagem individualmente).
Mostre o título utilizando um delimitador de variável literal ({{ ... }}
). Lembre-se que o post
será um objeto parecido com um dicionário para que você possa acessar o título da postagem com o post['title']
. Mostre também a data de criação da postagem usando o mesmo método.
Assim que terminar de editar o arquivo, salve e feche-o. Em seguida, vá até a página inicial em seu navegador. Você verá as duas postagens que adicionou ao banco de dados na sua página.
Com a função de visualização index()
modificada para exibir todas as postagens que você tem no banco de dados na página inicial do seu aplicativo, você continuará para exibir cada postagem em uma única página e permitir que os usuários se conectem a cada postagem individual.
Neste passo, você criará uma nova rota Flask com uma função de visualização e um novo modelo HTML para exibir uma postagem do blog pela sua ID.
Ao final deste passo, a URL http://127.0.0.1:5000/1
será uma página que mostra a primeira postagem (porque ela tem a ID 1
). A URL http://127.0.0.1:5000/ID
exibirá a postagem com o número de ID
associado a ela, se existir.
Abra o app.py
para edição:
- nano app.py
Como você precisará obter uma postagem do blog pela ID dela do banco de dados em vários locais mais à frente neste projeto, você criará uma função chamada get_post()
. É possível chamá-la passando a ela uma ID e receber a postagem do blog associada à ID fornecida, ou fazer o Flask responder com uma mensagem 404 Not Found
caso a postagem do blog não exista.
Para responder com uma página 404
, é necessário importar a função abort()
da bilbioteca Werkzeug
que foi instalada com o Flask na parte superior do arquivo:
import sqlite3
from flask import Flask, render_template
from werkzeug.exceptions import abort
. . .
Em seguida, adicione a função get_post()
logo após a função get_db_connection()
que você criou no passo anterior:
. . .
def get_db_connection():
conn = sqlite3.connect('database.db')
conn.row_factory = sqlite3.Row
return conn
def get_post(post_id):
conn = get_db_connection()
post = conn.execute('SELECT * FROM posts WHERE id = ?',
(post_id,)).fetchone()
conn.close()
if post is None:
abort(404)
return post
. . .
Esta nova função tem um argumento post_id
que determina qual postagem do blog deve ser retornada.
Dentro da função, utilize a função get_db_connection()
para abrir uma conexão do banco de dados e executar uma consulta SQL para pegar a postagem do blog associada ao valor do post_id
dado. Adicione o método fetchone()
para obter o resultado e armazená-lo na variável post
e feche a conexão. Se a variável post
tiver o valor None
, significa que nenhum resultado foi encontrado no banco de dados. Utilize a função abort()
que você importou antes para responder com um código de error 404
. A função terminará a execução. No entanto, se uma postagem for encontrada, retorna-se o valor da variável post
.
Adicione a seguinte função de visualização ao final do arquivo app.py
:
. . .
@app.route('/<int:post_id>')
def post(post_id):
post = get_post(post_id)
return render_template('post.html', post=post)
Nesta nova função de visualização, adicione uma regra de variável <int:post_id>
para especificar que a parte após a barra (/
) é um número inteiro positivo (marcado com o conversor int
) que você precisa acessar em sua função de visualização. O Flask reconhece isso e passa seu valor ao argumento de palavra-chave post_id
da sua função de visualização post()
. Em seguida, utilize a função get_post()
para obter a postagem do blog associada à ID especificada e armazenar o resultado na variável post
que você passa para um modelo post.html
que criará em breve.
Salve o arquivo app.py
e abra um novo arquivo de modelo post.html
para edição:
- nano templates/post.html
Digite o código a seguir neste novo arquivo post.html
. Esse código é parecido com o arquivo index.html
, exceto que ele exibirá apenas uma única postagem além de exibir também o conteúdo da postagem:
{% extends 'base.html' %}
{% block content %}
<h2>{% block title %} {{ post['title'] }} {% endblock %}</h2>
<span class="badge badge-primary">{{ post['created'] }}</span>
<p>{{ post['content'] }}</p>
{% endblock %}
Adicione o bloco title
que você definiu no modelo base.html
para fazer com que o título da página reflita o título da postagem exibida no cabeçalho <h2>
ao mesmo tempo.
Salve e feche o arquivo.
Agora, é possível acessar as URLs seguintes para ver as duas postagens que você tem em seu banco de dados e ver uma página que diz ao usuário que a postagem solicitada do blog não foi encontrada (já que não há postagem com um número de ID 3
até agora):
http://127.0.0.1:5000/1
http://127.0.0.1:5000/2
http://127.0.0.1:5000/3
Ao voltar para a página inicial, você vinculará cada título da postagem para sua página respectiva. Faça isso usando a função url_for()
. Primeiro, abra o modelo index.html
para edição:
- nano templates/index.html
Em seguida, altere o valor do atributo href
de #
para {{ url_for('post', post_id=post['id']) }}
para que o loop for
se pareça exatamente com o seguinte:
{% for post in posts %}
<a href="{{ url_for('post', post_id=post['id']) }}">
<h2>{{ post['title'] }}</h2>
</a>
<span class="badge badge-primary">{{ post['created'] }}</span>
<hr>
{% endfor %}
Aqui, passe o 'post'
para a função url_for()
como um primeiro argumento. Este é o nome da função de visualização post()
. Como ela aceita um argumento post_id
, dê a ela o valor post['id']
. A função url_for()
retornará a URL adequada para cada postagem baseada na ID dela.
Salve e feche o arquivo.
Agora, os links na página inicial funcionarão como esperado. Com isso, você terminou de desenvolver a parte do aplicativo responsável por exibir as postagens do blog em seu banco de dados. Em seguida, adicione os recursos de criar, editar e excluir postagens do blog ao seu aplicativo.
Agora que você terminou de exibir as postagens do blog que estão presentes no banco de dados no aplicativo Web, é necessário permitir que os usuários do seu aplicativo escrevam novas postagens no blog e as adicionem ao banco de dados, editem postagens existentes e excluam postagens desnecessárias no blog.
Até agora, você tem um aplicativo que exibe as postagens em seu banco de dados, mas não fornece uma maneira de adicionar uma nova postagem, a menos que, você se conecte diretamente ao banco de dados SQLite e a adicione manualmente. Nesta seção, você criará uma página na qual poderá criar uma postagem fornecendo seu título e conteúdo.
Abra o arquivo app.py
para editá-lo:
- nano app.py
Primeiro, você importará o seguinte do framework Flask:
request
global para acessar os dados de solicitação que serão enviados através de um formulário HTML.url_for()
para gerar URLs.flash()
para mostrar uma mensagem flash quando uma solicitação for processada.redirect()
para redirecionar o cliente para um local diferente.Adicione as importações ao seu arquivo como o seguinte:
import sqlite3
from flask import Flask, render_template, request, url_for, flash, redirect
from werkzeug.exceptions import abort
. . .
A função flash()
armazena mensagens flash na sessão do navegador do cliente, que exige a definição de uma chave secreta. Esta chave secreta é utilizada para sessões seguras, que permitem que o Flask lembre-se das informações de uma solicitação para outra, como mudar da nova página de postagem para a página inicial. Os usuários podem acessar as informações armazenadas na seção, mas não podem modificá-las se não tiverem a chave secreta. Desta forma, você nunca deve permitir que alguém tenha acesso a sua chave secreta. Consulte a documentação Flask para sessões para obter maiores informações.
Para definir uma chave secreta, você adicionará uma configuração SECRET_KEY
ao seu aplicativo através do objeto app.config
. Adicione-a diretamente seguindo a definição do app
antes de definir a função de visualização index()
:
. . .
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'
@app.route('/')
def index():
conn = get_db_connection()
posts = conn.execute('SELECT * FROM posts').fetchall()
conn.close()
return render_template('index.html', posts=posts)
. . .
Lembre-se de que a chave secreta deve ser uma string aleatória longa.
Após definir uma chave secreta, você criará uma função que renderizará um modelo que mostra um formulário onde é possível criar uma nova postagem do blog. Adicione esta nova função no final do arquivo:
. . .
@app.route('/create', methods=('GET', 'POST'))
def create():
return render_template('create.html')
Isso criar uma rota /create
que aceita as solicitações GET e POST. As solicitações GET são aceitas por padrão. Para também aceitar as solicitações POST, que são enviadas pelo navegador ao enviar formulários, você passará uma tupla com os tipos de solicitações aceitos para o argumento methods
do decorador @app.route()
.
Salve e feche o arquivo.
Para criar o modelo, abra um arquivo chamado create.html
dentro de sua pasta templates
:
- nano templates/create.html
Adicione o código a seguir dentro deste novo arquivo:
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Create a New Post {% endblock %}</h1>
<form method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title"
placeholder="Post title" class="form-control"
value="{{ request.form['title'] }}"></input>
</div>
<div class="form-group">
<label for="content">Content</label>
<textarea name="content" placeholder="Post content"
class="form-control">{{ request.form['content'] }}</textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
{% endblock %}
A maioria desse código é HTML padrão. Ele exibirá uma caixa de entrada para o título da postagem, uma área de texto para o conteúdo da postagem e um botão para enviar o formulário.
O valor da entrada do título da postagem é {{ request.form['title'] }}
e a área de texto tem o valor {{ request.form['content'] }}
. Isso é feito para que os dados que você digitou não sejam perdidos se algo der errado. Por exemplo, se você escrever uma postagem muito grande e esquecer de dar um título, aparecerá uma mensagem informando que está faltando o título. Isso acontecerá sem perder a postagem que você escreveu, pois ela estará armazenada no objeto global request
que você tem acesso em seus modelos.
Agora, com o servidor de desenvolvimento em execução, utilize seu navegador para acessar a rota /create
:
http://127.0.0.1:5000/create
Você verá uma página Create a New Post (Criar uma nova postagem) com uma caixa de texto para um título e um conteúdo.
Este formulário envia uma solicitação POST para sua função de visualização create()
. No entanto, ainda não há código para processar uma solicitação POST na função. Por este motivo, nada acontece após preencher e enviar o formulário.
Você tratará a solicitação POST que chegar quando um formulário for enviado. Isso será feito dentro da função de visualização create()
. É possível tratar as solicitações POST separadamente verificando o valor do request.method
. Quando seu valor for definido para 'POST'
, significa que a solicitação é um solicitação POST. Desta forma, você extrairá os dados enviados, os validará e os inserirá em seu banco de dados.
Abra o arquivo app.py
para editá-lo:
- nano app.py
Modifique a função de visualização create()
para ela se parecer exatamente como segue:
. . .
@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!')
else:
conn = get_db_connection()
conn.execute('INSERT INTO posts (title, content) VALUES (?, ?)',
(title, content))
conn.commit()
conn.close()
return redirect(url_for('index'))
return render_template('create.html')
Na instrução if
, você confirma que o código seguinte é executado apenas quando a solicitação for do tipo 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 dá a você o acesso aos dados do formulário na solicitação. Se o título não for fornecido, a condição if not title
estaria cumprida, mostrando uma mensagem ao usuário informando que o título é necessário. Se, por outro lado, o título for fornecido, abre-se uma conexão com a função get_db_connection()
e insere-se o título e o conteúdo recebido na tabela posts
.
Em seguida envie as alterações ao banco de dados e feche a conexão. Após adicionar a postagem do blog ao banco de dados, redirecione o cliente para a página inicial usando a função redirect()
passando à função a URL gerada pela função url_for()
com o valor 'index'
como um argumento.
Salve e feche o arquivo.
Agora, vá até a rota /create
utilizando seu navegador Web:
http://127.0.0.1:5000/create
Preencha o formulário com um título e um pouco de conteúdo à sua escolha. Assim que enviar o formulário, você verá a nova postagem listada na página inicial.
Por último, você exibirá mensagens flash e adicionará um link para a barra de navegação no modelo base.html
para ter um fácil acesso a esta nova página. Abra o arquivo de modelo:
- nano templates/base.html
Edite o arquivo adicionando uma nova tag <li>
seguindo o link About
dentro da tag <nav>
. 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:
<nav class="navbar navbar-expand-md navbar-light bg-light">
<a class="navbar-brand" href="{{ url_for('index')}}">FlaskBlog</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{url_for('create')}}">New Post</a>
</li>
</ul>
</div>
</nav>
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-danger">{{ message }}</div>
{% endfor %}
{% block content %} {% endblock %}
</div>
Salve e feche o arquivo. A barra de navegação terá agora um item New Post
vinculado à rota /create
.
Para que um blog esteja sempre atualizado, você precisará editar suas postagens existentes. Esta seção guiará você no processo de criação de uma nova página em seu aplicativo no intuito de simplificar o processo de edição de uma postagem.
Primeiro, você adicionará uma nova rota ao arquivo app.py
. Sua função de visualização receberá a ID da postagem que precisa ser editada. A URL estará no formato /post_id/edit
com a variável post_id
sendo a ID da postagem. Abra o arquivo app.py
para editá-lo:
- nano app.py
Em seguida, adicione a seguinte função de visualização edit()
ao final do arquivo. Editar uma postagem existente é parecido com a criação de uma postagem nova. Por este motivo, esta função de visualização se parecerá com a função de visualização create()
:
. . .
@app.route('/<int:id>/edit', methods=('GET', 'POST'))
def edit(id):
post = get_post(id)
if request.method == 'POST':
title = request.form['title']
content = request.form['content']
if not title:
flash('Title is required!')
else:
conn = get_db_connection()
conn.execute('UPDATE posts SET title = ?, content = ?'
' WHERE id = ?',
(title, content, id))
conn.commit()
conn.close()
return redirect(url_for('index'))
return render_template('edit.html', post=post)
A postagem que você edita é determinada pela URL e o Flask passará o número da ID para a função edit()
através do argumento id
. Adicione este valor à função get_post()
para obter a postagem associada à ID fornecida do banco de dados. Os novos dados virão em uma solicitação POST que é processada dentro da condição if request.method == 'POST'
.
Assim como no processo de criação de uma nova postagem, você deve primeiro extrair os dados do objeto request.form
e depois criar uma mensagem flash se o título tiver um valor vazio. Se o título não estiver vazio, abra uma conexão ao banco de dados. Em seguida, atualize a tabela posts
definindo um novo título e um novo conteúdo onde a ID da postagem no banco de dados é igual a ID que estava na URL.
No caso de uma solicitação GET, você renderiza um modelo edit.hmlt
passando na variável post
que contém o valor retornado da função get_post()
. Você utilizará isso para exibir o título e o conteúdo existentes na página de edição.
Salve e feche o arquivo. Em seguida, crie um novo modelo edit.html
:
- nano templates/edit.html
Escreva o código a seguir dentro deste novo arquivo:
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Edit "{{ post['title'] }}" {% endblock %}</h1>
<form method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title" placeholder="Post title"
class="form-control"
value="{{ request.form['title'] or post['title'] }}">
</input>
</div>
<div class="form-group">
<label for="content">Content</label>
<textarea name="content" placeholder="Post content"
class="form-control">{{ request.form['content'] or post['content'] }}</textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
<hr>
{% endblock %}
Salve e feche o arquivo.
Este código segue o mesmo padrão, exceto pelas sintaxes {{ request.form['title'] or post['title'] }}
e {{ request.form['content'] or post['content'] }}
. Isso mostra os dados armazenados na solicitação se eles existirem, caso contrário, ele exibe os dados da variável post
que foram passados para o modelo contendo os dados do banco de dados atual.
Agora, vá para a seguinte URL para editar a primeira postagem:
http://127.0.0.1:5000/1/edit
Você verá uma página Edit “First Post”.
Edite a postagem e envie o formulário. Em seguida, confirme que a postagem foi atualizada.
Agora, é necessário adicionar um link que aponta para a página de edição de cada postagem na página inicial. Abra o arquivo de modelo index.html
:
- nano templates/index.html
Edite o arquivo para que ele se pareça exatamente com o seguinte:
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% for post in posts %}
<a href="{{ url_for('post', post_id=post['id']) }}">
<h2>{{ post['title'] }}</h2>
</a>
<span class="badge badge-primary">{{ post['created'] }}</span>
<a href="{{ url_for('edit', id=post['id']) }}">
<span class="badge badge-warning">Edit</span>
</a>
<hr>
{% endfor %}
{% endblock %}
Salve e feche o arquivo.
Aqui, adicione uma tag <a>
para vincular a função de visualização edit()
passando o valor post['id']
para vincular a página de edição de cada postagem com o link Edit
.
Às vezes, não é mais necessário que uma postagem esteja disponível ao público. Por este motivo, é fundamental termos a funcionalidade de excluir uma postagem. Neste passo, você adicionará a funcionalidade de exclusão ao seu aplicativo.
Primeiro, adicione uma nova rota /ID/delete
que aceita as solicitações POST, que se assemelha à função de visualização edit()
. Sua nova função de visualização delete()
receberá a ID da postagem que será excluída da URL. Abra o arquivo app.py
:
- nano app.py
Adicione a seguinte função de visualização no final do arquivo:
# ....
@app.route('/<int:id>/delete', methods=('POST',))
def delete(id):
post = get_post(id)
conn = get_db_connection()
conn.execute('DELETE FROM posts WHERE id = ?', (id,))
conn.commit()
conn.close()
flash('"{}" was successfully deleted!'.format(post['title']))
return redirect(url_for('index'))
A função de visualização aceita somente as solicitações POST. Isso significa que ao acessar a rota /ID/delete
em seu navegador, um erro retornará, pois os navegadores Web aceitam somente solicitações GET por padrão.
No entanto, é possível acessar essa rota através de um formulário que envia uma solicitação POST que passa a ID da postagem que você deseja excluir. A função receberá o valor da ID e o utilizará para obter a postagem do banco de dados com a função get_post()
.
Em seguida, abra uma conexão do banco de dados e execute um comando SQL DELETE FROM
para excluir a postagem. Confirme as alterações feitas ao banco de dados e feche a conexão, crie uma mensagem flash para informar ao usuário que a postagem foi excluída com sucesso e redirecione os usuários para a página inicial.
Note que desta vez você não renderizará um arquivo de modelo, pois você adicionará um botão Delete
à página de edição.
Abra o arquivo de modelo edit.html
:
- nano templates/edit.html
Em seguida, adicione a seguinte tag <form>
após a tag <hr>
e diretamente antes da linha {% endblock %}
:
<hr>
<form action="{{ url_for('delete', id=post['id']) }}" method="POST">
<input type="submit" value="Delete Post"
class="btn btn-danger btn-sm"
onclick="return confirm('Are you sure you want to delete this post?')">
</form>
{% endblock %}
Use o método confirm()
para exibir uma mensagem de confirmação antes de enviar a solicitação.
Agora, vá novamente para a página de edição de uma postagem do blog e tente excluir a postagem:
http://127.0.0.1:5000/1/edit
Ao final deste passo, o código-fonte do seu projeto se parecerá com o código desta página.
Com isso, os usuários do seu aplicativo poderão escrever novas postagens e as adicionar ao banco de dados, editar e excluir postagens existentes.
Este tutorial introduziu conceitos essenciais do framework Python Flask. Você aprendeu como criar um aplicativo Web pequeno, executá-lo em um servidor de desenvolvimento e permitir que os usuários forneçam dados personalizados através de parâmetros URL e formulários Web. Você também usou o mecanismo modelo do Jinja para reutilizar arquivos HTML e utilizar lógica neles. Ao final deste tutorial, você criou um blog da Web totalmente funcional que interage com um banco de dados SQLite para criar, exibir, editar e excluir postagens de um blog usando a linguagem Python e as consultas SQL.
Você pode desenvolver ainda mais este aplicativo, adicionando a autenticação de usuários para que apenas usuários registrados possam criar e modificar postagens do blog. Também é possível adicionar comentários e tags para cada postagem do blog e adicionar uploads de arquivos para que os usuários possam incluir imagens nas postagens. Consulte a documentação Flask para obter maiores informações.
O Flask tem muitas extensões Flask feitas pela comunidade. Considere utilizar esta lista de extensões a seguir para facilitar seu processo de desenvolvimento:
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Have you this tutorial for windows ?
Ótimo tutorial! Muito esclarecedor! Parabéns à equipe.