Nosso projeto já sofreu umas refatorações e hoje teremos mais uma.
Mas antes, lembram do nosso arquivo .flaskenv? Com a contribuição do @loscinco, que falou algo que esqueci ontem, além da variável de ambiente FLASK_APP apontar para app, devemos, em ambiente de desenvolvimento, que é o caso, setar a variável FLASK_ENV para development, assim:

Essa variável apontando para development vai ativar o debug e outras coisas, como facilitar o processo de auto reload dos templates ao mudarmos algo no template, fazer com que alguma alteração no código Python já seja enviada para o servidor local, etc. Ajuda bastante no desenvolvimento e eu tinha esquecido de adicionar.
Agora vamos mudar algumas coisas no nosso projeto. Vamos aprender herança de templates.
Ontem criamos duas novas rotas e duas novas views. A rota que vai abrir dados do Brasil e a rota que vai abrir dados do mundo, com suas respectivas views.
@app.route('/brasil')
def brazil():
return "<h1>Hello Brasil!</h1>"
@app.route('/mundo')
def world():
return "<h1>Hello Mundo!</h1>"
Mas se eu abri uma rota exclusiva para dados do Brasil, meu index.html tem que mudar, já que atualmente está assim:

Vamos mudar essa tela inicial para um texto qualquer, e criar um arquivo dentro da pasta templates com o nome "brazil.html".
Vamos copiar o código do "index.html" para o "brazil.html":

O código vai ser igual ao do index.html:
<!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>
<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 class="collapse navbar-collapse" id="navbar-content">
<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>
</div>
</div>
</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>
<!-- 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>
Basta eu ir lá no site e clicar na aba Brasil, correto?

Errado! Se eu só criar o template e não fizer mais nada, o resultado será o mesmo de ontem:

Alguma suspeita do que devemos fazer?
Vou parar 3 segundos pra vocês pensarem...
1...
2...
3...
Se não veio a luz, eu preciso ir lá no meu routes.py e fazer com que a função responsável por essa rota, nossa função de view, renderize o template recém-criado, mas para dar tudo certo e ele renderizar os dados, eu preciso passar a função de view do index para a função de view da rota "brasil":
# 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():
pass
@app.route('/brasil')
def brazil():
# Fazendo a requisição para a API
request = requests.get('h t t p s : / / a p i . c o v id19.finspect.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('brazil.html', states=states_data, date=date)
@app.route('/mundo')
def world():
return "<h1>Hello Mundo!</h1>"
Percebam a linha do render_template, que agora renderiza o template "brazil.html".
Rodando o projeto e digitando na barra de navegação o endpoint /brasil, teremos:

E se eu for na minha rota raiz agora?

Bem-vindos ao debugger do Flask. O fato de setarmos a variável de ambiente FLASK_ENV para development logo no início deste tópico habilita o debugger e podemos debuggar nosso código mais facilmente.
Observem a mensagem de erro:
TypeError: the view function did not return a valid response. The function either returned None or ended without a return statement.
Fiz isso de propósito. Ao copiar o código da função index para a função brazil eu deixei lá só a palavra reservada "pass", mas toda função de view deve retornar alguma coisa.
Vamos fazer com que ela retorne o template index.html:
# Criando nossa primeira rota
@app.route("/")
def index():
return render_template("index.html")
O site:

Tudo certo, né? Como eu não passei mais os dados, e meu index.html ainda está igual ao brazil.html, a tabela é criada mas sem dado nenhum.
Mas como falei, quero o index.html mostrando uma mensagem de página inicial, algo bem básico.
Vamos alterar o index.html para o código abaixo:
<!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>
<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 class="collapse navbar-collapse" id="navbar-content">
<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>
</div>
</div>
</nav>
<div class="container">
<h1 class="text-center mb-3">
Dados sobre a Covid-19 no Brasil e no mundo
</h1>
<div class="row">
<div class="col-md-7">
<p class="text-justify">
Este é um site informativo sobre a Covid-19, doença causada pelo
novo coronavírus (Sars-Cov-2).
</p>
<p class="text-justify">
O site acessa dados desta
<a href="https://doc.covid.finspect.me/">API</a>, que busca dados do
DATASUS, e desta
<a href="https://rapidapi.com/Gramzivi/api/covid-19-data/details"
>API</a
>, que contém dados do mundo.
</p>
<p>
Site em construção.
</p>
</div>
<div class="col-md-5">
<div class="card bg-light mb-3">
<div class="card-header">Números do mundo</div>
<div class="card-body">
<h5 class="card-title">Dados totais</h5>
<ul class="list-group">
<li class="list-group-item">
Confirmados:
<span></span>
</li>
<li class="list-group-item">Recuperados: <span></span></li>
<li class="list-group-item">Mortes: <span></span></li>
</ul>
</div>
</div>
</div>
</div>
</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>
Como já dito, não vou me ater a detalhes do HTML neste projeto, o foco é back-end e como renderizar esses dados do back no front. Estilização vou passar por cima.
Basicamente eu criei um título, um texto e uma lista que irá mostrar os casos confirmados, o número de mortes e o número de recuperados no mundo.
Rodando nosso site ele está assim agora no index.html:

Esse quadro com essa lista de confirmados, recuperados e mortes vamos buscar em API também, mas não é assunto pra hoje.
O foco do tópico de hoje é agora. Programador odeia código repetido. Fora que não é nada produtivo.
Parem e pensem no que temos de comum entre o template index e o template brazil.
Nossa barra de navegação, certo?
E o que acontece se eu quiser adicionar mais um link na barra de navegação?
Digamos que eu queira criar um novo endpoint para notícias. Aí vou lá no index.html:
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a href="#" class="nav-link">Notícias</a>
</li>
<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>
E acesso meu index.html:

Mas se eu acessar o endpoint brasil, minha barra de navegação estará assim:

Notaram a diferença? O link para notícias só existe no index.html. E natural, só alterei lá.
Mas isso é fácil, né? Basta eu ir no brazil.html e adicionar o link para notícias também e tudo certo.
...
Mais ou menos, né...
Imaginem uma barra de navegação com 10 links (muitos, como é aqui na Bastter.com).
E 10 páginas que eu terei que adicionar cada link novo criado.
Isso com certeza não é nada produtivo, nada eficaz. É contraproducente.
Para evitar esse tipo de retrabalho, nós vamos criar um template base e fazer com que todos os outros templates usem essa base nos seus HTML.
Vamos para a pasta templates e criemos um "base.html":

Nesse base.html iremos adicionar tudo que é comum às outras páginas.
A parte comum é toda a tag <head>, que importa o CSS, etc, além das tags <script>, que trazem o javascript para nossa página, e também o conteúdo da navbar:
<!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>
<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 class="collapse navbar-collapse" id="navbar-content">
<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>
</div>
</div>
</nav>
<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>
E como eu faço para que as outras páginas puxem esses dados base?
Eu insiro esse conteúdo extra por meio de blocos de código entre chaves com os símbolo de percentual em cada lado e a palavra reservada do flask "block", com o conteúdo sendo representado por uma palavra qualquer.
Observem o que tá depois do fechamento da tag nav acima, temos as tags script.
Logo depois da tag nav eu vou inserir um container e inserir esses blocos de código. Assim:
</nav>
<div class="container">
{% block content %}
{% endblock %}
</div>
<script
Vamos lá para nosso index.html agora e apagar tudo que é comum às páginas. Ou seja, a tag <head>, os scripts, a navbar, e deixar só o que é diferente. Mas logo acima eu preciso inserir isto aqui:
{% extends "base.html" %}
Em seguida, insiro o mesmo código de block content e endblock, indicando que o que vem dentro dele vai ser inserido no template base:
{% extends "base.html" %}
{% block content %}
<!-- html a ser introduzido -->
{% endblock %}
Vai ficar assim:
{% extends "base.html" %}
{% block content %}
<h1 class="text-center mb-3">
Dados sobre a Covid-19 no Brasil e no mundo
</h1>
<div class="row">
<div class="col-md-7">
<p class="text-justify">
Este é um site informativo sobre a Covid-19, doença causada pelo novo
coronavírus (Sars-Cov-2).
</p>
<p class="text-justify">
O site acessa dados desta
<a href="https://doc.covid.finspect.me/">API</a>, que busca dados do
DATASUS, e desta
<a href="https://rapidapi.com/Gramzivi/api/covid-19-data/details">API</a>,
que contém dados do mundo.
</p>
<p>
Site em construção.
</p>
</div>
<div class="col-md-5">
<div class="card bg-light mb-3">
<div class="card-header">Números do mundo</div>
<div class="card-body">
<h5 class="card-title">Dados totais</h5>
<ul class="list-group">
<li class="list-group-item">
Confirmados:
<span></span>
</li>
<li class="list-group-item">Recuperados: <span></span></li>
<li class="list-group-item">Mortes: <span></span></li>
</ul>
</div>
</div>
</div>
</div>
{% endblock %}
Agora se eu rodar meu projeto:

Meu index.html "herdou" os dados do base.html e renderizou o conteúdo normalmente na página.
Vamos alterar também o brazil.html, a fim de evitar repetição de código:
{% extends "base.html" %}
{% block content %}
<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>
{% endblock %}
Abrindo o endpoint /brasil agora:

Tudo certo. Consegui herdar novamente.
Vamos fazer o mesmo com o endpoint /mundo. Vamos criar um world.html e herdar o conteúdo de base.html:

O html:
{% extends "base.html" %}
{% block content %}
<h1>Hello {{ world }}! (Literally)</h1>
{% endblock %}
Lembrando que preciso alterar a view function no routes.py:
@app.route("/mundo")
def world():
return render_template("world.html", world="World")
Acessando o endpoint /mundo:

Agora só falta eu conseguir voltar pro meu index.html. O ideal é ao clicar no logo Covid-19 eu conseguir voltar para o index.
Vamos no template base, o base.html, e alterar esta linha:
<nav class="navbar navbar-expand-lg navbar-dark bg-dark text-white mb-4">
<div class="container">
<a href="{{ url_for('index') }}" class="navbar-brand">Covid-19</a>
<button
class="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbar-content"
>
Olhem a linha do link do logo. Adicionei no href a url para a função index, e agora ao clicarmos na logo somos levados de volta para a página inicial.

E o recado de hoje era esse, herança de templates.