Neste artigo vou desenvolver uma CRUD utilizando o Flask e o Jinja2 e explicar algumas funcionalidades deles.
O que é Flask e porque ele é considerado um microframework?
Flask é um microframework para aplicações web utilizando Python. Ele é classificado como microframework porque precisa do mínimo de configuração possível – mantém o core da aplicação simples e deixa você livre para escolher o que usar em sua aplicação (por exemplo, seu banco de dados).
Por default ele não tem camada de abstração de banco de dados, mecanismo de validação de formulário e afins, mas suporta extensões que realizam integrações com banco de dados, requisições, validações de formulários, autenticação, upload de arquivos, entre outras.
Resumindo: você pode utilizar do Flask tudo o que precisa e dispensar tudo o que não precisa no momento.
Jinja2 – Mecanismo de template para Python
Jinja é um mecanismo de templates para Python. Ele facilita a tarefa de usar HTML dentro de nossas aplicações Python, tem completo suporte unicode, e para aplicativos que necessitam de maior segurança, adiciona execução em área restrita e escape automático.
A sintaxe dos templates Jinja é semelhante a essa:
Seu modo de execução é em sandbox (é semelhante à usar uma máquina virtual, porém, altamente focado na segurança da aplicação, semelhante ao modo privado dos navegadores. Todos os seus aspectos de execução são monitorados e adicionados na lista de permissões ou na lista negra).
É possível utilizar o mesmo layout ou layouts semelhantes para todos os modelos graças ao recurso da herança.
O Jinja traduz as fontes do seu template no primeiro carregamento para o bytecode do Pyhton, just in time na compilação.
Sistema de depuração que integra erros de tempo de execução de modelos e erros de compilação no sistema padrão de rastreamento de erros do Python.
Vamos ao código?
Ao final teremos uma aplicação semelhante a esta – é necessário ter o Python e o Flask instalados:
Primeiramente, vamos criar o server que será o arquivo pokedex.py:
from flask import Flask, render_template, request, redirect, session, flash, url_for
#render template: passando o nome do modelo e a variáveis ele vai renderizar o template
#request: faz as requisições da nosa aplicação
#redirect: redireciona pra outras páginas
#session: armazena informações do usuário
#flash:mensagem de alerta exibida na tela
#url_for: vai para aonde o redirect indica
app = Flask(__name__)
app.secret_key = 'flask'
#chave secreta da sessão
class Pokemon:
def __init__(self, nome, especie, tipo):
self.nome = nome
self.especie = especie
self.tipo = tipo
class Treinadora:
def __init__(self, id, nome, senha):
self.id = id
self.nome = nome
self.senha = senha
#criação das terindoras
treinadora1 = Treinadora('Mary', 'Mary Jackson ', '1234')
treinadora2 = Treinadora('Ada', 'Ada Lovelace', '1234')
treinadora3 = Treinadora('Katherine', 'Katherine Johnson', '1234')
treinadoras = {treinadora1.id: treinadora1,
treinadora2.id: treinadora2,
treinadora3.id: treinadora3}
#base de dados de pokemons
pokemon1 = Pokemon('Meowth', 'Arranha Gato', 'Normal')
pokemon2 = Pokemon('Charmander', 'Lagarto', 'Fogo')
pokemon3 = Pokemon('Clefairy', 'Fada', 'Fada')
pokemon4 = Pokemon('Machop', 'Superpoder', 'Lutador')
pokemon5 = Pokemon('Rhyhorn', 'Espigão', 'Terrestre/pedra')
pokemon6 = Pokemon('Cyndaquil', 'Rato de fogo', 'Fogo')
pokemon7 = Pokemon('Shuckle', 'Mofo', 'Pedra')
pokemon8 = Pokemon('Whismur', 'Sussuro', 'Normal')
pokemon9 = Pokemon('Swablu', 'Pássaro de algodão', 'Voador')
pokemon10 = Pokemon('Bidoof', 'Rato Gorducho', 'Normal')
lista = [pokemon1, pokemon2,pokemon3,pokemon4,pokemon5,pokemon6,pokemon7,pokemon8,pokemon9,pokemon10]
#configuração da rota index.
@app.route('/')
def index():
return render_template('lista.html', titulo='Pokedex', pokemons=lista)
#renderizando o template lista e as variáveis desejadas.
#configuração da rota novo, ela só poderá ser acessda se o usuário estiver logado, caso contrário redireciona para a tela de login
@app.route('/novo')
def novo():
if 'usuario_logado' not in session or session['usuario_logado'] == None:
return redirect(url_for('login', proxima=url_for('novo')))
return render_template('novo.html', titulo='Novo Pokemon')
#renderiza o template novo
#configuração da rpta criar que usa o método post para enviar dados dos nossos pokemons
@app.route('/criar', methods=['POST',])
def criar():
nome = request. form['nome']
especie = request. form['especie']
tipo = request. form['tipo']
pokemon = Pokemon(nome, especie, tipo)
lista.append(pokemon)
return redirect(url_for('index'))
#já inclui o novo pokemon na lista e joga na tela inicial
#configuração da rota login
@app.route('/login')
def login():
proxima = request.args.get('proxima')
return render_template('login.html', proxima=proxima)
#configuração da rota autenticar que verific as credenciais das terinadoras
@app.route('/autenticar', methods=['POST', ])
def autenticar():
if request.form['treinadora'] in treinadoras:
treinadora = treinadoras[request.form['treinadora']]
if treinadora.senha == request.form['senha']:
session['usuario_logado'] = treinadora.id
flash(treinadora.nome + ' acesso permitido!')
proxima_pagina = request.form['proxima']
return redirect(proxima_pagina)
else:
#caso as credenciais não sejam validadas, exibe mensagem de erro e redirecion para o login
flash('Acesso negado, digite novamente!')
return redirect(url_for('login'))
#configuração da rota logout
@app.route('/logout')
def logout():
session['usuario_logado'] = None
flash('Treinadora, logue novamente para cadastrar os pokemons que encontrar!')
return redirect(url_for('index'))
app.run(debug=True)
Agora criaremos os templates que serão renderizados. Crie a pasta templates, e dentro dela crie o arquivo template.html, que será o “pai” dos nossos templates.
Nos templates usaremos o Jinja2, que é o foco deste artigo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pokedex</title>
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap.css') }}">
</head>
<body>
<div class="container">
<!--cria container onde as mensagens serão exibidas-->
{% with messages = get_flashed_messages() %}
{% if messages %}
<!--condição para exibição das mensagens-->
<ul id="messages" class="list-unstyled">
<!--laço e repetição para exibição das mensagens-->
{% for message in messages %}
<li class="alert alert-success">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<!--fim dos laços-->
<div class="page-header">
<h1>{{ titulo }}</h1>
</div>
{% block conteudo %}{% endblock %}
</div>
<a class="btn btn-primary" href="/login" role="button">Login </a>
<a class="btn btn-primary" href="/novo" role="button">Novo </a>
<a class="btn btn-primary" href="/logout" role="button">Logout </a>
</body>
</html>
Nesta pasta, também crie o lista.html.
{% extends "template.html" %}
<!--criamos um bloco de conteúdo a ser interpretado pelo python-->
{% block conteudo %}
<table class="table table-striped table-responsive table-bordered">
<thead>
<tr>
<th>Nome</th>
<th>Espécie</th>
<th>Tipo</th>
</tr>
</thead>
<tbody>
<!--criamos uma estrutura de repetição com o Jinja2 para preencher nossa tabela com os dados dos pokemons-->
{% for pokemon in pokemons %}
<tr>
<td>{{ pokemon.nome }}</td>
<td>{{ pokemon.especie }}</td>
<td>{{ pokemon.tipo }}</td>
<!--acessamos os atributos nome, espécie e tipo de cada pokemon-->
</tr>
{% endfor %}
<!--encerramos a estrutura de repetição-->
</tbody>
</table>
{% endblock %}
<!--encerramos o bloco de código a ser interpretado pelo python-->
Nesta mesma pasta criaremos o template login.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pokedex</title>
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap.css') }}">
</head>
<body>
<div class="container">
<!--criamos um container que vai exibir as mensagens de alerta-->
{% with messages = get_flashed_messages() %}
{% if messages %}
<!--condição para as mensagens-->
<ul id="messages" class="list-unstyled">
<!--criamos um laço de repetição para essas mensagens de alerta-->
{% for message in messages %}
<li class="alert alert-success">{{ message }}</li>
<!--chamada da mensagem-->
{% endfor %}
<!--fim do for-->
</ul>
{% endif %}
<!--fim do if-->
{% endwith %}
<h1>Faça seu login</h1>
<form method="POST" action="{{ url_for('autenticar') }}">
<input type="hidden" name="proxima" value="{{ proxima or url_for('index') }}">
<p><label>Nome da treinadora:</label> <input class="form-control" type="text" name="treinadora" required></p>
<p><label>Senha:</label> <input class="form-control" type="password" name="senha" required></p>
<p><button class="btn btn-primary" type="submit">Entrar</button></p>
</form>
</div>
</body>
</html>
Agora vamos ao template novo.html:
{% extends "template.html" %}
{% block conteudo %}
<form action="{{ url_for('criar') }}" method="post">
<fieldset>
<div class="form-group">
<label for="nome">Nome</label>
<input type="text" id="nome" name="nome" class="form-control">
</div>
<div class="form-group">
<label for="categoria">Espécie</label>
<input type="text" id="especie" name="especie" class="form-control">
</div>
<div class="form-group">
<label for="console">Tipo</label>
<input type="text" id="tipo" name="tipo" class="form-control">
</div>
<button type="submit" class="btn btn-primary btn-salvar">Registrar na pokedex</button>
</fieldset>
</form>
{% endblock %}
O bootstrap deste projeto se encontra aqui. Crie uma pasta na raiz, chamada static, e dentro dela coloque este arquivo bootstrap.css.
Seu projeto deverá estar com uma estrutura semelhante a esta:
Para executar é necessário rodar o comando python pokedex.py.
Referências utilizadas e repositório com o código:
- Kamilahsantos/Flask–Crud
- Welcome | Flask (A Python Microframework)
- Welcome | Jinja2 (The Python Template Engine)
- Quickstart — Flask 1.0.2 documentation
- O que é Sandbox?
- Flask parte 1: Crie uma webapp com Python 3
- Flask-Session — Flask-Session 0.3.0 documentation
- Top 10 Python Web Frameworks to Learn in 2018 – Hacker Noon
- Python Flask Introdução