CS50

CS50x em Português - Aula 9 - Flask: summary

YouTube summary37 sectionsWatch on YouTube ↗

This is an AI-generated summary of the YouTube video "CS50x em Português - Aula 9 - Flask" (CS50), made with Samuraize and published by Samuraize. It condenses the YouTube video into 37 titled sections you can read in a couple of minutes, each linking to the moment in the video it covers.

1
Filed under🎓 Education0 comments🍱 Add to trayReport
Study this
Export

CS50x em Português - Aula 9 - Flask

CS50

A semana 9 e a síntese do curso 0:43

A aula abre explicando que a semana 9 é a mais representativa do que significa programar de fato, pois reúne quase tudo visto nas dez semanas anteriores. O foco agora é aplicar essas ferramentas a um problema novo, a programação web, unindo o lado do cliente, feito com HTML e JavaScript, a um componente do lado do servidor, escrito em Python e SQL, permitindo criar aplicações web completas e, se o aluno quiser, também aplicativos móveis para o projeto final.

De arquivos para rotas 3:00

Até a semana anterior, as URLs correspondiam literalmente a arquivos ou pastas no servidor, como arquivo.html ou pasta/. A partir de agora, o conceito muda para rotas, isto é, caminhos que o próprio código do servidor interpreta como entrada para decidir o que responder, em vez de apontarem diretamente para um arquivo físico. O exemplo dado é o /search do Google, que não corresponde a nenhuma pasta, apenas a um programa que recebe o parâmetro q=cats como entrada. Parâmetros continuam sendo passados após um ponto de interrogação, no formato chave=valor, separados por e comercial quando há mais de um.

Por que usar Flask 4:02

Escrever um servidor web do zero em C seria impraticável, então o curso adota Python e, mais especificamente, o Flask, descrito como um micro framework: uma biblioteca de código feita por outras pessoas para facilitar a criação de aplicações web, somada a um conjunto de convenções a seguir. O Flask já resolve tarefas repetitivas, como tratar requisições GET e POST e extrair pares chave-valor das URLs, dispensando que cada programador reimplemente isso. Para rodar uma aplicação Flask, basta ter na pasta um arquivo app.py e, idealmente, um requirements.txt listando as bibliotecas usadas, instaláveis via pip install flask.

O primeiro app.py 9:32

O código mínimo importa a função Flask do pacote flask, cria uma variável app que transforma o arquivo em aplicação, e define uma função chamada index que retorna o texto 'Hello, world'. O decorador @app.route('/') associa essa função à rota raiz do site. Executando flask run, o servidor sobe na porta 5000, diferente da porta 8080 usada pelo http-server da semana anterior. Inspecionando o código-fonte da página, percebe-se que o navegador recebeu apenas a string de texto, sem HTML real, e foi o próprio navegador que preencheu a estrutura mínima para exibi-la.

Retornando HTML e usando templates 14:30

É possível fazer a função retornar uma string completa de HTML, com doctype, head, title e body, e o navegador então exibe a página como esperado. Mas isso é pouco prático, então o curso introduz render_template, função que busca arquivos HTML dentro de uma pasta chamada templates, separando a lógica em Python do layout em HTML, assim como já se fazia fatoração de CSS e JavaScript na semana anterior.

Capturando entrada do usuário com request.args 17:05

Para exibir um nome vindo da URL, como ?name=David, o Flask oferece a variável global request.args, um dicionário com os parâmetros da requisição. O valor é passado para o template através de um argumento nomeado, e dentro do index.html usa-se pares de chaves, como em hello, {{placeholder}}, para que a biblioteca Jinja, incluída no Flask, interpole o valor real no lugar do espaço reservado. Isso mostra que o conteúdo vem do servidor, não do lado do cliente, já que o código-fonte da página exibe diretamente o nome inserido.

Tratando a ausência do parâmetro 23:30

Se o usuário acessa a rota sem passar name, o Flask responde com um erro HTTP 400, indicando requisição inválida, o que é uma experiência ruim já que nenhum usuário digita URLs manualmente. A solução é usar um condicional em app.py que verifica se name está em request.args, atribuindo o valor recebido quando presente ou um valor padrão como 'world' quando ausente, garantindo que a aplicação sempre responda corretamente.

Valores ausentes e request.args 25:02

Um aluno pergunta o que acontece se o parâmetro name for passado sem valor na URL. O professor testa e mostra que a chave name continua presente no dicionário request.args, só que sem valor associado, então a lógica condicional continua funcionando normalmente. Isso serve para reforçar a utilidade do Flask: basta importar a variável global request e perguntar se um parâmetro existe, sem precisar escrever código para separar manualmente a URL em pontos de interrogação, sinais de igual e comerciais.

Simplificando com request.args.get 27:02

O professor mostra que é convencional no Flask usar o mesmo nome para a variável Python e para o placeholder do template, como name igual a name, o que deixa o código mais claro do que usar nomes genéricos como placeholder. Em seguida, ele reduz quatro linhas de código a uma só, usando a função get do dicionário request.args, que busca o parâmetro name e, caso ele não exista, retorna um valor padrão como mundo. Isso mantém a mesma lógica anterior de forma muito mais compacta.

Criando um formulário e a rota greet 28:31

O professor decide substituir o preenchimento manual da URL por um formulário real em index.html, com um campo de texto chamado name, placeholder, autofoco e um botão de envio chamado saudar. A ação do formulário aponta para uma nova rota, slash greet, que ainda não existe no app.py. Ele então cria essa rota, definindo uma função greet que renderiza um novo template chamado greet.html, passando o nome capturado via request.args.get. Ao testar, o navegador mostra um erro interno do servidor, código 500, e o terminal revela a causa real: o arquivo greet.html ainda não foi criado, algo que o usuário final não vê por motivos de segurança.

Duplicação e o template layout.html 36:02

Depois de criar greet.html com o mesmo HTML repetido de index.html, o professor observa que quase todo o código dos dois arquivos é idêntico, exceto pelo conteúdo do corpo da página. Para eliminar essa duplicação, ele cria um terceiro arquivo, layout.html, colocando nele todo o HTML repetitivo e usando a sintaxe do Jinja, a biblioteca de templates do Flask, com chaves e sinais de porcentagem para marcar um bloco chamado body. Os arquivos index.html e greet.html passam então a apenas estender layout.html e preencher esse bloco com o conteúdo específico de cada página, o que reduz bastante o código repetido.

GET, POST e privacidade dos dados 43:02

O professor alerta que usar o método GET em formulários expõe os dados diretamente na barra de URL, o que é um problema de privacidade se envolver senhas, números de cartão ou termos de busca sensíveis. Ele muda o formulário para o método POST e mostra, usando a aba de rede do inspecionar do navegador, que os dados passam a ir no corpo da requisição em vez da URL, sendo acessados no servidor por request.form em vez de request.args. Ele também explica que é preciso declarar explicitamente methods igual a uma lista com POST na rota, já que o Flask assume GET por padrão.

Unindo as rotas com lógica condicional 48:00

Por fim, o professor propõe eliminar a duplicação de rotas, já que ter uma rota só para mostrar o formulário e outra para processá-lo dobra o número de rotas necessárias conforme a aplicação cresce. Ele reescreve a rota index para aceitar tanto GET quanto POST, usando um if para verificar o método da requisição: se for POST, o formulário foi enviado e o código chama render_template para greet.html com o nome do usuário; caso contrário, assume-se GET e mostra-se apenas o formulário em index.html. Assim, toda a lógica de saudação fica concentrada em uma única rota.

Simplificando o formulário e a rota padrão 51:00

Rafael ajusta o formulário para que ele envie os dados para a mesma rota de onde veio, eliminando a necessidade de apontar explicitamente para /greet. Ele mostra que, ao usar POST em vez de GET, os dados enviados não aparecem na URL, o que é bom por questões de privacidade. Também demonstra como usar lógica condicional dentro do template Jinja, testando se a variável name tem valor para exibir ou o nome do usuário ou, na ausência dele, a palavra world como padrão, tudo isso usando a sintaxe if e endif do Jinja.

Espaços em branco e documentação do Jinja 53:00

Rafael explica por que o espaço extra dentro do template não quebra o layout: o HTML ignora espaços em branco supérfluos e os colapsa em um único espaço, o mesmo fenômeno visto na aula anterior com os parágrafos do texto do pato. Ele indica a documentação oficial do Flask e do Jinja como referência para quem quiser explorar mais recursos de lógica dentro dos templates.

A origem do exemplo Frosh IMs 54:00

Rafael conta que, quando fez CS50 no seu segundo ano, não havia programação web no curso, e a internet ainda era muito nova. Pouco depois, ele se envolveu no Programa Esportivo Intramural de Calouros, onde os alunos se inscreviam em esportes preenchendo uma folha de papel e deslizando-a por debaixo da porta do tutor. Motivado por isso, ele aprendeu Perl e arquivos CSV para construir um site que permitia aos alunos se inscreverem em esportes digitando o nome e selecionando a modalidade, eliminando a necessidade do papel físico. Esse projeto serve de motivação para reconstruir, em Flask, uma versão simplificada do site Frosh IMs.

Construindo o formulário de inscrição 56:00

No diretório froshims, Rafael monta o index.html com um formulário que envia dados por POST para a rota /register. O formulário inclui uma caixa de texto para o nome, com placeholder, autofocus e autocomplete desativado, além de um menu suspenso (select) com as opções basquete, futebol e ultimate frisbee, cada uma com seu próprio value. Ele adiciona uma opção em branco selecionada por padrão para evitar que o usuário se inscreva acidentalmente em basquete sem escolher nada, e finaliza com um botão do tipo submit rotulado Registrar.

Criando a rota de registro e as páginas de resultado 1:03:02

Rafael cria em app.py a rota /register aceitando o método POST, que verifica, usando request.form.get, se o usuário informou nome e esporte. Se algum estiver ausente, o sistema renderiza failure.html, avisando que o usuário não está registrado; caso contrário, renderiza success.html, confirmando o registro. Ao testar, ele encontra e corrige um erro de aspas não fechadas no template, mostrado pela mensagem de erro no terminal do Flask, e confirma que o fluxo de sucesso e falha funciona corretamente.

A vulnerabilidade do menu suspenso e a validação no servidor 1:08:01

Rafael demonstra, usando as ferramentas de desenvolvedor do navegador, como um usuário mal-intencionado, batizado de Kelly, pode editar o HTML da página para adicionar uma opção de vôlei que não existia no menu original e se inscrever nela mesmo assim, provando que a validação feita apenas no HTML do lado do cliente não é suficiente. Para corrigir isso, ele mostra que validar cada esporte manualmente em app.py duplicaria a lista de esportes já presente no template. A solução mais elegante é criar uma variável global chamada SPORTS em app.py, verificar no servidor se o esporte enviado está nessa lista, e passar essa mesma lista para o template usando render_template, de modo que o index.html gere as opções do menu dinamicamente com um loop for do Jinja, eliminando duplicidade e bloqueando tentativas como a de Kelly.

Botões de rádio como alternativa ao menu suspenso 1:15:00

Para encerrar, Rafael mostra outra forma de coletar a escolha do esporte: em vez do menu suspenso, ele começa a construir um conjunto de botões de rádio, gerados dinamicamente por um loop pelos esportes da lista global, cada input do tipo radio compartilhando o mesmo nome sport para garantir que apenas uma opção possa ser selecionada por vez.

Botões de rádio no formulário 1:16:01

Você retoma o formulário de inscrição mostrando como o navegador exibe botões de rádio mutuamente exclusivos quando os inputs compartilham o mesmo nome. Ao ver o código-fonte da página, os três inputs gerados dinamicamente têm todos type igual a radio e o mesmo atributo name, e é isso que garante que só um possa ser selecionado. Do lado do servidor nada muda: request.form continua entregando nome e esporte da mesma forma, independentemente do tipo de campo usado no navegador.

Mensagens de erro mais claras 1:17:02

Você percebe que dizer apenas "você não está registrado" é uma péssima experiência de usuário quando alguém esquece o nome ou o esporte. Para resolver isso, cria um template error.html que estende layout.html e exibe um título "error" e um parágrafo com uma mensagem a ser definida. No app.py, valida separadamente o nome, o esporte e se o esporte está na lista de esportes válidos, retornando render_template de error.html com mensagens específicas como "nome ausente", "esporte ausente" ou "esporte inválido". No caminho, você corrige um erro de digitação em que escreveu "body block" em vez de "block body", e depois de testar no navegador confirma que agora cada falta de informação gera uma mensagem própria e mais explicativa.

Guardando inscritos em memória 1:22:01

Você cria uma variável global chamada registrants, um dicionário vazio, para guardar o nome e o esporte de cada aluno inscrito. Na rota de registro, cada novo aluno é adicionado ao dicionário usando o nome como chave e o esporte como valor. Depois cria uma nova rota, /registrants, que renderiza um template registrants.html mostrando uma tabela HTML com colunas de nome e esporte, gerada dinamicamente com um laço for do Jinja, do mesmo jeito que Gmail ou Outlook provavelmente geram linha por linha de uma caixa de entrada. Você também adiciona um link "veja quem mais se registrou" na página de sucesso, e depois substitui esse link por um redirect automático para /registrants usando a função redirect do Flask, de forma que o usuário é levado direto à lista após se inscrever.

O problema da memória volátil 1:30:00

Você mostra que, ao reiniciar o servidor Flask (por exemplo depois de editar o código), a variável global registrants é apagada, porque vivia apenas na memória RAM do processo. Isso significa que qualquer pessoa inscrita antes do reinício desaparece da lista, o que é claramente inaceitável para um site real. A solução é parar de guardar os dados numa variável global e passar a guardar num banco de dados persistente.

Migrando para SQLite com a biblioteca CS50 1:31:30

Você importa a função SQL da biblioteca do CS50 e cria uma conexão com um banco chamado froshims.db, que já tem uma tabela registrants com colunas id, name e sport, sendo id a chave primária e name e sport marcados como not null. Na rota de registro, troca a gravação no dicionário por um comando SQL de INSERT usando marcadores de posição (nunca f-strings), para evitar ataques de injeção de SQL. Na rota /registrants, troca a leitura do dicionário por um SELECT que devolve uma lista de dicionários, e ajusta o template para iterar sobre essa lista em vez de um único dicionário. Depois de testar, você reinicia o servidor Flask e confirma que os inscritos continuam lá, provando que agora os dados sobrevivem a reinicializações.

Cancelando inscrições pelo ID 1:37:30

Você propõe adicionar um botão de "cancelar registro" para cada linha da tabela de inscritos. Como pode haver mais de uma pessoa com o mesmo nome, a exclusão deve usar o id único de cada registro, que é a chave primária vista na semana 7, e não o nome. Você acrescenta uma terceira coluna na tabela com um formulário HTML cuja ação é uma rota /deregister usando o método POST, com um botão de envio rotulado "cancelar registro" e um campo oculto (type hidden) contendo o id do inscrito daquela linha. No processo, você comete e corrige um pequeno erro de digitação, usando "registrants" no lugar de "registrant" dentro do laço for, o que fazia o campo aparecer em branco.

Excluindo registros com uma nova rota 1:42:00

David volta ao VS Code para criar a rota /deregister, que lê o ID do formulário enviado pelo botão de cada inscrito e, se o ID existir, executa um DELETE FROM registrants WHERE id = ? no banco de dados, redirecionando o usuário de volta para a página de inscritos. Ao testar, aparece o erro 'método não permitido', porque a rota estava configurada apenas para GET enquanto o formulário usa POST. Depois de ajustar a rota para aceitar methods=['POST'], a exclusão funciona e Kelly, e depois o próprio David, desaparecem da lista de inscritos, o que é confirmado com um SELECT no terminal.

Por que usar POST em vez de GET 1:46:32

David explica por que escolheu POST deliberadamente para o formulário de cancelamento de inscrição. O motivo não é tanto esconder o ID na URL, já que os IDs são só números sem significado pessoal, mas sim evitar que uma simples visita a um link possa alterar dados. Com GET, um link como /registrants?id=4 poderia ser enviado por e-mail a um fiscal, e um clique ingênuo apagaria o registro de Doug sem querer, abrindo espaço para ataques de phishing. Com POST, é preciso clicar num botão explícito, o que serve como camada extra de proteção sempre que uma ação altera ou identifica dados no servidor.

Exibindo imagens com a pasta static 1:47:33

Para deixar a mensagem de erro mais amigável, David tenta inserir a imagem de um gato usando uma tag img comum, mas ela aparece quebrada porque o arquivo cat.jpg está na pasta errada. Ele explica que, no Flask, qualquer recurso estático como imagens, CSS ou JavaScript precisa ficar dentro de uma pasta chamada static, por ser conteúdo imutável que não muda dinamicamente como app.py. Depois de mover o arquivo para essa pasta e ajustar o caminho para /static/cat.jpg no template, a imagem aparece corretamente, ao contrário da pasta templates, que o render_template já localiza automaticamente sem precisar ser mencionada no caminho.

Permitindo múltiplas inscrições com checkboxes 1:50:32

Para deixar o site mais prático, David troca os botões de rádio por checkboxes no formulário, permitindo que uma pessoa se inscreva em vários esportes de uma vez. Isso exige mudar a lógica em app.py, usando request.form.getlist para capturar uma lista de esportes em vez de um único valor, e depois percorrer essa lista tanto para validar cada esporte quanto para inserir uma linha por esporte no banco de dados. O teste mostra David inscrito em basquete e futebol simultaneamente, mas ele nota um problema de design: o nome dele fica duplicado na tabela, e o ideal seria ter uma tabela separada de alunos com IDs próprios, evitando essa redundância.

O padrão Model-View-Controller 1:55:02

David situa o que foi construído dentro do paradigma comum chamado MVC, Model-View-Controller. A view é a interface que o usuário vê e manipula, como os templates HTML. O controller é a lógica de negócios, representada pelo app.py, que gera essas views. E o model é onde os dados persistem, que evoluiu de um simples dicionário em memória para o banco de dados froshims.db. Ele ressalta que essa divisão não é perfeitamente limpa, já que variáveis e loops também aparecem nas views, mas serve como uma mentalidade geral útil para organizar aplicações web.

Cookies e como sites lembram o login 2:01:00

David explica como sites como o Gmail lembram que você já fez login por dias ou semanas usando cookies, um recurso do HTTP. Quando você envia um formulário de login, o servidor responde com um cabeçalho set-cookie contendo um par chave-valor, geralmente uma string aleatória única, que o navegador passa a reenviar automaticamente em cada requisição futura, como um carimbo de mão que você mostra repetidamente para entrar e sair de um lugar sem pagar de novo. Ele adverte que armazenar senhas diretamente em cookies é arriscado, e que anunciantes usam esse mesmo mecanismo para reconhecer visitantes repetidos entre sites, motivo pelo qual a navegação anônima apaga os cookies ao fechar a janela.

Sessões e o início do exemplo de login 2:02:31

David introduz o conceito de sessão, um recurso que dá a ilusão de uma conexão persistente entre navegador e servidor mesmo sendo o HTTP, por natureza, sem estado. Em Python, uma sessão pode ser tratada como um dicionário de pares chave-valor associado a cada usuário, mantido no servidor graças aos cookies. Ele então abre um novo diretório de exemplo chamado login, que usa a biblioteca Flask-Session para gerenciar isso automaticamente, sem exigir que o programador entenda os detalhes técnicos dos cabeçalhos HTTP. Ao testar o site, a página inicial mostra se o usuário está ou não logado, e ao preencher apenas um nome de usuário e clicar em login, o sistema passa a exibir 'estou logado como David' e oferece um link de logout, demonstrando o comportamento típico de sistemas de autenticação.

Login e logout com sessões 2:06:31

O código de app.py mostra como funciona a rota de login: se a requisição chega por POST, o valor digitado no formulário é guardado na sessão sob a chave name, e o usuário é redirecionado para a página inicial. O template index.html decide o que mostrar com uma lógica condicional simples: se houver um nome guardado na sessão, exibe uma mensagem de boas-vindas e um link para sair; se não houver, mostra um link para entrar. Fazer logout é tão simples quanto chamar session.clear, o que apaga os dados do lado do servidor associados ao cookie do usuário, desconectando-o imediatamente, mesmo que o endereço na barra do navegador nem pareça mudar.

Carrinho de compras com sessão 2:09:00

Um exemplo de loja virtual simples, guardado num banco de dados chamado store.db, vende cinco livros, entre eles O Guia do Mochileiro das Galáxias. A página inicial lista os livros com botões de Adicionar ao Carrinho, cada um enviando por POST o ID oculto do livro para a rota /cart. Essa rota guarda numa lista dentro da sessão os IDs escolhidos, começando com uma lista vazia caso o usuário ainda não tenha nada no carrinho. Depois de adicionar, a mesma rota, acessada por GET, busca no banco de dados os livros cujos IDs estão na sessão e os exibe na página do carrinho, mostrando por que a sessão funciona como a melhor metáfora para entender esse mecanismo: cada usuário tem sua própria versão privada desse dicionário, mesmo estando todos no mesmo site.

Mecanismo de busca de programas 2:16:01

Um terceiro exemplo, chamado shows, usa o mesmo banco de dados de séries do IMDb já visto em semanas anteriores. A primeira versão implementa uma busca simples que só encontra títulos exatos, como The Office em maiúsculas específicas. A segunda versão melhora isso usando a palavra-chave LIKE em SQL, combinada com o sinal de porcentagem antes e depois do termo digitado, permitindo encontrar qualquer trecho do título sem se importar com maiúsculas ou minúsculas. É mostrado também que, ao rodar o Flask no terminal, aparecem em cores os comandos SQL enviados ao banco, o que ajuda a depurar erros relacionados a consultas.

Autocomplete e dados em JSON 2:20:32

Uma versão mais interativa do buscador de séries dispara uma requisição a cada letra digitada, sem precisar de botão de busca, imitando o autocomplete visto antes com JavaScript. Nas ferramentas de desenvolvedor, a aba de rede mostra que cada letra gera uma nova chamada à rota /search, que primeiro devolve apenas trechos de HTML prontos e depois, numa versão final, devolve os dados brutos em JSON, o formato JavaScript Object Notation que se parece com listas e dicionários do Python. Para isso o código usa a função jsonify do Flask, que transforma os resultados do banco em JSON, permitindo que o próprio aplicativo ou terceiros consumam esses dados como uma API, do mesmo jeito que a API da OpenAI enviava respostas em semanas anteriores. Com isso encerra-se o conteúdo de programação web do curso, que vai da semana 0 até esta semana 9, restando apenas a última semana do curso.

AI-generated summary. It can be wrong or incomplete - check anything that matters against the original.

Summarize your own YouTube video

Paste a YouTube link, article, PDF, ebook or slide deck and get a summary like this in seconds. Free to try, no sign-up needed.

⚔️ Try the YouTube summarizer

Discussion

Sign in to join the discussion. Sign in

More from the Bento Box

Browse the Bento Box →

We use Microsoft Clarity and Google Analytics to see what breaks and where visitors come from. They set cookies and send data to the US. Product events are counted without cookies either way. Cookie details