Ontem o tópico foi pesado mas já fizemos o deploy da nossa aplicação. Quem caiu de para-quedas por aqui e não sabe do que tou falando, estamos desenvolvendo um projeto na raça aqui de um site informativo sobre a Covid-19, que está disponível neste link:
Covid-19Até o momento, no nosso projeto dos tópicos, só temos uma página principal, que lista os casos da doença por estado. Falta um pouco para chegar ao estado do nosso site acima, no qual já vemos um site um pouco mais estruturado, com dados separados entre Brasil e Mundo, alguns gráficos do Brasil (falta inserir gráficos mundiais, que vão dar mais trabalho), etc.
Mas vamos chegar lá. Me empolguei com esse projeto e já dei uma andada boa nele, vamos ver o que falta para chegar lá.
Ontem fizemos o deploy da aplicação. Mas não temos mais como rodar nosso projeto localmente. Ele roda perfeito na web mas não roda mais localmente.
Para conseguirmos rodar nosso projeto localmente, vamos precisar instalar mais uma library, a python-dotenv, que basicamente envia dados de variáveis de ambiente (vamos ver o que são daqui a pouco) para nosso programa.
Antes, eu rodava o programa com um "app.run()" dentro do main.py, que nem existe mais. Agora eu preciso setar uma variável de ambiente apontando para meu app que está no pacote "app", que é a pasta "app" que vimos ontem.

Então, vamos instalar a python-dotenv:
(venv) $ Projetos/covid master
> pip install python-dotenv
Agora, vamos criar um arquivo na raiz do nosso projeto, com o nome ".flaskenv" (isso mesmo, com um ponto na frente, é uma forma de dizer que esse arquivo é um arquivo de variáveis de ambiente), e digitar isto aqui:

FLASK_APP é nossa variável de ambiente. É ela que o Python vai procurar na hora que digitarmos no terminal o comando abaixo:
(venv) $ Projetos/covid master
> flask run
Como ela está apontando para nosso "app", que é onde temos a nossa aplicação Flask, o Python vai conseguir criar o servidor local e teremos esta mensagem no terminal:
* Serving Flask app "app"
* 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)
Acessando o link:

Tudo como antes, nada mudou. Mas vimos que agora conseguimos novamente rodar nosso servidor local.
Agora, observando a tela acima, vemos que ela está um pouco diferente da tela inicial da aplicação que está rodando na web:

Claro, o conteúdo da tabela acima não está mais na página inicial. Eu joguei esse conteúdo para a URL Brasil, que está logo acima na barra de navegação, e nos mostra agora esta tela:

Vejam que as duas telas acima compartilham dados iguals, que é a barra de navegação de nosso site, que ainda não existe no nosso projeto.
Vamos criá-la.
Obs: este não é um projeto focado em front-end, então não vou me alongar explicando classes do Bootstrap, ou como criar uma barra de navegação, senão não terminaremos nunca se eu for abordar front-end, back-end e ainda a parte de deploy rs.
Abrindo nosso index.html, que até o momento está assim:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
crossorigin="anonymous"
/>
<title>Covid-19</title>
</head>
<body>
<div class="container">
<h1 class="text-center">Casos de Covid-19 no Brasil</h1>
<p class="text-center">
Dados por estado da federação, atualizados em {{ date }}
</p>
<!-- Tabela criada já com as classes Bootstrap -->
<table class="table table-striped">
<thead>
<tr>
<th scope="col">Estado</th>
<th scope="col">Número de casos</th>
</tr>
</thead>
<tbody>
<!-- Laço for agora iterando sobre cada estado do JSON -->
{% for state in states %}
<tr scope="row">
<!-- Os dados do laço -->
<td>{{ state["name"] }}</td>
<td>{{ state["qtd_confirmation"] }}</td>
</tr>
<!-- No template nós devemos sinalizar o fim do for com um endfor -->
{% endfor %}
</tbody>
</table>
</div>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"
></script>
<script
src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"
></script>
</body>
</html>
Vamos inserir uma tag <nav> logo abaixo da abertura do body:
<body>
<nav></nav>
<div class="container">
<h1 class="text-center">Casos de Covid-19 no Brasil</h1>
<p class="text-center">
Dados por estado da federação, atualizados em {{ date }}
</p>
Dentro dessa tag nav, vamos inserir as classes necessárias do Bootstrap:
<nav
class="navbar navbar-expand-lg navbar-dark bg-dark text-white mb-4"
></nav>
Como falei, o foco do projeto não é detalhar front-end, mas basicamente o que essas classes vão fazer é criar um estilo padrão para a barra de navegação, fazê-la responsiva, adicionar um fundo escuro (dark) e um texto branco (text-white), com um margin-bottom de 4 no Bootstrap, que corresponde a 1,5x o valor padrão que seria 24px.
Rodando nosso projeto com um flask run agora nós já vemos uma barra em formação logo acima:

Vejam a barra negra logo acima do título. É nossa futura barra de navegação.
Como eu quero o texto dentro dela com margens laterais, vou inserir todo o conteúdo da navbar dentro de uma div com a classe container:
<nav class="navbar navbar-expand-lg navbar-dark bg-dark text-white mb-4">
<div class="container"></div>
</nav>
E agora vamos jogar conteúdo nesse container. Vamos inserir um texto em um link que será uma espécie de "logo" do nosso site:
<nav class="navbar navbar-expand-lg navbar-dark bg-dark text-white mb-4">
<div class="container">
<a href="#" class="navbar-brand">Covid-19</a>
</div>
</nav>
A classe "navbar-brand" é uma classe do Bootstrap para criar um estilo para a logo.
Rodando agora nós veremos isto:

Agora uma coisa meio chata que pode estar acontecendo. Se eu atualizar qualquer coisa no index.html, se eu atualizar a página a alteração não vai ser mostrada.
Se eu mudar o link de "Covid-19" para "Covid-29" o link lá acima ainda vai estar "Covid-19".
Podemos resolver isso indo lá no nosso config.py e adicionando a variável de configuração TEMPLATE_AUTO_RELOAD do Flask com valor True:
# config.py
import os
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY')
TEMPLATES_AUTO_RELOAD = True
Agora se eu mudar algo no index.html não preciso mais rodar o flask com o run toda vida.
Voltando à nossa navbar. Já temos uma logo, agora precisamos adicionar um botão que vai aparecer no nosso site responsivo:

O Bootstrap faz isso de uma forma padrão bem fácil.
Do lado do meu link com a logo, vamos adicionar uma tag button:
<nav class="navbar navbar-expand-lg navbar-dark bg-dark text-white mb-4">
<div class="container">
<a href="#" class="navbar-brand">Covid-19</a>
<button
class="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbar-content"
>
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
O botão tem que ter a classe navbar-toggler, para indicar que este botão terá a função de trazer os dados da nossa barra de navegação no modo responsivo.
Os atributos data-toggle indicam a classe "collapse" que vai vir logo abaixo, e data-target indica o id da div que virá abaixo. Como falei, o foco aqui não é front-end então vou passar meio atropelado mesmo nisso aqui.
A tag span representa o ícone do botão em si. Experimentem apagar essa tag e vocês não verão o botão.
Salvando nosso index.html e agora atualizando nossa página, se diminuirmos a largura da página já é possível ver nosso botão:

Que se eu clicar não faz nada ainda.
Vamos criar o conteúdo que vai aparecer no botão quando ele for clicado, e na barra de navegação sem estar em modo responsivo:
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbar-content">
</div>
A classe collapse se comunica com o data-toggle do botão. A navbar-collapse faz parte desse comportamento que veremos no botão. O id é importante, pois é esse id que o data-target do button vai procurar e fazer com que o conteúdo seja exibido no clique.
Agora dentro de nossa div com a classe collapse vamos criar uma lista de links, que serão os links do nosso site. No site que está no ar temos dois links, "Brasil" e "Mundo". Vamos criar esses links:
<div class="collapse navbar-collapse" id="navbar-content">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a href="#" class="nav-link">Brasil</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link">Mundo</a>
</li>
</ul>
</div>
Atualizando:

E no modo responsivo agora ao clicarmos no botão ele irá mostrar os links:

Para finalizar, vamos criar mais duas rotas no routes.py, a rota que vai ter os dados do Brasil e a rota que vai ter os dados do mundo, abaixo nosso routes.py até o momento:
# routes.py
from app import app # aqui precisamos importar o app criado no __init__.py
from flask import render_template
import requests
from datetime import datetime
# Criando nossa primeira rota
@app.route('/')
def index():
# Fazendo a requisição para a API
request = requests.get('h t t p s : / / a p i . c o v i d 1 9 . f i nspect.me/brcovid19/map')
# Atribuindo o JSON recebido a uma variável
states_data = request.json()
# Pegando a data atual
date = datetime.now().strftime(format="%d/%m/%Y")
return render_template('index.html', states=states_data, date=date)
@app.route('/brasil')
def brazil():
return "<h1>Hello Brasil!</h1>"
@app.route('/mundo')
def world():
return "<h1>Hello Mundo!</h1>"
Agora precisamos linkar nosso index.html com essas funções de "view". View porque são essas funções que são responsáveis por nos mostrar o que nós vemos na tela.
Voltando ao index.html, eu preciso usar um código Python dentro do atributo href de cada link da barra de navegação, indicando que aquele link vai levar à função que eu vou inserir ali. Para isso vou usar a função url_for do Flask:
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a href="{{ url_for('brazil') }}" class="nav-link">Brasil</a>
</li>
<li class="nav-item">
<a href="{{ url_for('world') }}" class="nav-link">Mundo</a>
</li>
</ul>
Observem que eu passo como parâmetro uma string indicando o nome da função de view, e não do endpoint.
No caso do Brasil, a função tem nome brazil e o endpoint brasil. Aqui eu segui a padronização de código em inglês e só escrever em português coisas que o usuário vai ver como endpoints.
Agora, ao clicar em um link da barra de navegação, o Flask vai fazer com que seja renderizado na tela o conteúdo de cada função de view, seja a função "brazil", seja a função "world".
Se eu clicar na barra de navegação em Brasil:

Serei direcionado para esta página, o endpoint brasil:

A mesma coisa se eu clicar no "Mundo":

Vejam as URLs de cada página acima, indicando a rota que eu atribuí no routes.py. Vamos relembrar:
@app.route('/brasil')
def brazil():
return "<h1>Hello Brasil!</h1>"
@app.route('/mundo')
def world():
return "<h1>Hello Mundo!</h1>"
Então, recapitulando, a rota "/brasil" aciona a função "brazil", que mostra o "Hello Brasil!" na tela. E na barra de navegação, o "url_for('brazil')" é o comando responsável por me enviar para o endpoint "/brasil". A mesma coisa no endpoint "/mundo".
Por hoje acho que tá bom. Amanhã vamos começar a ver como vamos transformar essas duas páginas nestas páginas abaixo:


Ps: acabei de perceber que o título da página do Brasil "Dados de Covid-19 no Brasil e no Mundo" não faz sentido já que são só dados brasileiros. Vou alterar agora

.