diff --git a/mod-12/README.md b/mod-12/README.md new file mode 100644 index 0000000..347ee29 --- /dev/null +++ b/mod-12/README.md @@ -0,0 +1,386 @@ +# Módulo 12 + +## Índice + + 1. [Introdução ao Flask](#objetos-imutáveis) + 2. [Variáveis do Ambiente Flask](#objetos-mutáveis) + 3. [Listando Eventos](#definindo-classes) + 4. [Detalhar Evento](#herança) + 5. [Lidando com erros no Flask](#exercícios) + 6. [Criar Novo Evento](#exercícios) + 7. [Deletar Evento](#exercícios) + 8. [Editar Evento (PUT)](#exercícios) + 9. [Editar Evento Parcial (PATCH)](#exercícios) + +## Criando Projeto Django + +Como no flask, vamos criar um ambiente virtual para usar neste projeto do Django. Assim, dentro da pasta do projeto usamos: + +```python +python -m venv venv +``` + +> Nota: se antes de criar o `venv` você abrir o VS Code na pasta do projeto, a `venv` criada vai ser automaticamente reconhecida e indicada pelo VS Code a ser utilizada como interpretador padrão para o projeto + +Criado a *venv*, precisamos agora instalar dentro dela o Django com o comando abaixo: + +> Nota: +> - de dentro do VS Code, ao abrir o terminal Git Bash, a `venv` já estará ativa +> - de fora, ativamos a `venv` de 2 maneiras: +> > 1.se na `venv` tiver a pasta `bin`, ativamos com `source venv/bin/activate` +> > +> > 2.caso haja `Scripts`, usar `source venv/Scripts/activate` + +```python +django-admin startproject nome_pjt . +``` + +Após o comando acima, será criado uma pasta com o *nome_pjt* passado e outro arquivo `manage.py` com algumas funcionalidades do Django + +Agora já podemos rodar um servidor com o seguinte comando: + +```python +python manage.py runserver +``` + +No linux, Ubuntu numa VM VirtualBox, o python está na versão 3.8 e +precisou instalar o `sudo apt install python3.8-venv` para conseguir criar o `venv` no projeto + +No python 3.8 ainda existe a pasta bin com o activate dentro e +ativei com `source venv/bin/activate` + +Em seguida, instalei o django com `pip install django` e já instalou a mais atual 4.0.3 + +Para criar o projeto django usei +`django-admin startproject nome_pjt lcl_server`, criando assim: + +```python +django-admin startproject torneios . +``` + +O django criou uma pasta com o nome "torneios" e deixou nosso servidor `manage.py` em `.` onde foi executado o comando + +## Criando nosso app + +Com o Django, nossas funcionalidades serão modularizadas com o uso de apps e cada app representará uma funcionalidade completa, como se o app ficasse responsável por uma parte completamente funcional do projeto + +Com isso, no nosso servidor que receberá as requisições, vamos direcionar os pedidos de uma parte do projeto para nosso app em criação + +```python +# criando nosso app +django-admin startapp agenda +``` + +Assim como no Flask, no Django também referenciamos uma url de requisição para uma função, ou view + +Porém, no Django, incluímos esses caminhos em um arquivo diferente do qual executamos o servidor + +Como vimos, nosso servidor encontra-se no `manage.py` e o direcionamento, ou roteamento, das urls fica dentro da pasta principal do projeto em `urls.py` + +Dentro de `urls.py` vamos incluir um caminho com `path(caminho, view)` +na lista de `urlpatterns` indicando pro servidor quem responderá ao pedido + +```python +# arquivo urls.py na pasta principal +# primeiro importamos a função +from agenda.views import index +urlpatterns = [ + path('admin/', admin.site.urls), + # depois incluímos o caminho + path("agenda", index), +] + +# views.py dentro de agenda +# abaixo de "Create your views" +def index(request): + return HttpResponse("Olá mundo") +``` + +Assim, quando acessamos nosso domínio no caminho `agenda` o servidor encaminhará para a função `index` dentro da *`views.py`* da nossa app agenda + +Como boa prática, podemos também incluir um arquivo `urls.py` da pasta agenda inteiro no `path` para direcionar todos os pedidos ao caminho `agenda` ao app agenda + +Assim, sempre que uma requisição com o caminho iniciado por `agenda` chegar ao servidor, encaminhamos ao nosso app agenda a responsabilidade de respondê-la + +Logo, no arquivo `urls.py` do projeto, incluiremos: + +```python +# urls.py do projeto +# com o *as* damos um apelido diferente +# ao padrão de urls da agenda +from agenda.urls import urlpatterns as agenda_urls +urlpatterns = [ + path("agenda", include(agenda_urls)) +] +``` + +Desta forma, informamos ao nosso servidor que quando o caminho tiver *agenda* nele, o app agenda vai tratar os pedidos de requisição e o arquivo `urls.py` de agenda passa a rotear as requisições + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Criando Models e Exibir Torneio + +Quando criamos nosso app com o Django o arquivo `models.py` vai nos ajudar a declarar nossas entidades + +Neste arquivo teremos as classes com as quais iremos trabalhar no projeto declarando seus atributos e métodos aqui + +```python +# no model.py do app +class Inscrito: + id = 0 + def __init__(self, nome, local) -> None: + Inscrito.id += 1 + self.id = Inscrito.id + self.nome = nome + self.local = local + self.inscricoes = [] +class Competicao: + id = 0 + def __init__(self, nome, data): + Competicao.id += 1 + self.id = Competicao.id + self.qtd_inscritos = 0 + self.nome = nome + self.data = data + self.inscritos = [] +# código para teste vem aqui também +# neste caso criei 2 torneios +disp1 = Competicao("xadrez","05/03/2022") +disp2 = Competicao("matematica","04/03/2022") +# depois incluí ambos numa lista +disputas = [] +disputas.append(disp1) +disputas.append(disp2) +``` + +Agora vamos mostrar uma tabela listando as competições criadas + +Primeiro incluiremos na `urls.py` da agenda um caminho que responderá pela requisição, então: + +```python +# urls.py da agenda +from django.urls import path +from agenda.views import agenda_mostra_disputas + +urlpatterns = [ + path("/disputas", agenda_mostra_disputas), +] +``` + +Agora, criamos a função em `views.py` do app agenda para responder os pedidos + +```python +def agenda_mostra_disputas(request): + return render( + request=request, + context={"table_linhas": disputas}, + template_name="agenda/exibe_disputa.html", + ) +``` + +No próximo capítulo explico melhor a linha com `template_name="agenda/exibe_disputa.html",` passado para o render + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Utilizando Django Template + +Agora com os *templates* vamos conseguir separar códigos html do nosso código python + +Assim vamos criar uma pasta *templates/nome_app* dentro de nosso app para dentro dela criar nossos arquivos com código html personalizado que será atualizado dinamicamente quando executarmos o programa + +Então, dentro da nossa pasta `templates/agenda` vamos criar um arquivo `exibe_disputas.html` para colocar dentro dele todo o html que vamos precisar + +> ```html +> +> +>

Disputa: {{disputa.id}}

+>

Id: {{disputa.id}}

+>

Nome: {{disputa.nome}}

+>

Data: {{disputa.data}}

+> +> ``` + +> Nota1: +> > no VS Code é possível selecionar o modo de linguagem para o Django HTML para formatar o arquivo html direitinho +> +> Nota2: +> > no arquivo template também é possível inserir alguns códigos nele como um `if` ou `for` para gerar as linhas de uma tabela ou filtrar algo que não queremos que seja mostrado, no arquivo fica assim: +> ```html +> {% for item in table_linhas %} +> +> {{ item.id }} +> {{ item.nome }} +> {{% if %}{{ item.data }}{% endif %} +> +> {% endfor %} +> ``` + +Para importar nosso arquivo template precisamos chamar na view o *loader* do Django da seguinte maneira: + +```python +# dentro de nossa view importamos +from django.template import loader +# criamos referência ao template +template = loader.get_template("agenda/exibe_disputa.html") +``` + +Depois de todo esse processo ainda precisamos informar ao Django que nosso app existe e qual o seu nome + +No arquivo `settings.py` localizado na pasta do projeto principal temos que incluir um item na lista `INSTALLED_APPS` com a linha a seguir: + +> ```python +> INSTALLED_APPS = [ +> ... # código existente +> 'agenda.apps.AgendaConfig', +> ] +> ``` + +Por fim, após a requisição ser roteada pelo urls do app e direcionada a função da nossa view, esta retornará com o uso de um `render` a página construída com o código estático e dinâmico interpolado num só da seguinte maneira + +> ```python +> return render( +> request=request, +> context={"table_linhas": disputas}, +> template_name="agenda/exibe_disputa.html", +> ) +> ``` + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Trabalhando com Bancos de Dados + +Neste capítulo vamos apresentar muito por alto a ideia de um banco de dados relacional no qual gravaremos de forma mais persistente, nossas entidades e suas relações entre todas elas + +Imaginem o seguinte baseado no exemplo já comentado, no qual vamos controlar competições e as pessoas cadastradas e inscritas em cada uma + +Num banco de dados, salvaremos nossos objetos em tabelas que representam a classe deles e em alguns casos também teremos tabelas para representar as relações entre as entidades + +Nos nossos exemplos usaremos o Django ORM para fazer a persistência dos nossos objetos + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Django ORM e migrações + +Agora vamos ver alguns exemplos do uso do Django ORM com o SQLite porém, futuramente migraremos para o Postgres + +O ORM em Django ORM significa Object Relational Mapping, ou um mapeamento de objetos relacionais e faz com que as entidades com seus atributos e seus relacionamentos sejam gravados em tabelas no banco de dados + +Primeiramente precisamos ir em nosso arquivo `models.py` dentro do nosso app e fazer com que o django saiba que uma classe dali será persistida no banco como uma tabela da seguinte forma: + +```python +# dentro de models.py do app +# declaramos a classe assim +class Categoria(models.Model): + nome = models.CharField(max_length=60, unique=True) +``` + +No código acima precisamos que a classe herde de `models.Model` para que o Django saiba que aquela classe será gravada no banco de dados e na linha `nome = models.CharField(max_length=60, unique=True)` dizemos que o atributo *nome* será na tabela do tipo *CharField* de tamanho 60 e que o valor será único não podendo ter outro registro igual na tabela + +Agora precisamos enviar essas alterações para o arquivo de banco de dados executando no terminal o seguinte + +```python +python manage.py makemigrations +``` + +Dentro da pasta `migrations` do nosso app será criado um arquivo sequencial que terá comandos a serem executados para atualizar nosso banco conforme as alterações feitas no projeto + +Após a geração deste arquivo podemos efetivar essas alterações no banco com o comando a seguir: + +```python +python manage.py migrate +``` + +Para verificar se tudo funcionou temos o comando `python manage.py dbshell` que inicia o shell do SQLite e nele podemos digitar `.tables` para ver as tabelas criadas no banco + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Fazendo consultas pelo Shell + + + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Django Admin + + + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Listagem de Eventos + + + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Adicionando Data aos Eventos + + + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Buscando e Exibindo Evento + + + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Navegando entre Páginas do app + + + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + +## Enviando um Formulário + + + +--- + +[Voltar ao Topo](#m%C3%B3dulo-12) + +--- + diff --git "a/mod-13/exerc\303\255cios/Captura de Tela (32).png" "b/mod-13/exerc\303\255cios/Captura de Tela (32).png" new file mode 100644 index 0000000..c4d61cb Binary files /dev/null and "b/mod-13/exerc\303\255cios/Captura de Tela (32).png" differ diff --git "a/mod-13/exerc\303\255cios/Captura de Tela (33).png" "b/mod-13/exerc\303\255cios/Captura de Tela (33).png" new file mode 100644 index 0000000..f3eba18 Binary files /dev/null and "b/mod-13/exerc\303\255cios/Captura de Tela (33).png" differ diff --git "a/mod-13/exerc\303\255cios/calculadora_de_notas.py" "b/mod-13/exerc\303\255cios/calculadora_de_notas.py" new file mode 100644 index 0000000..b9bbae0 --- /dev/null +++ "b/mod-13/exerc\303\255cios/calculadora_de_notas.py" @@ -0,0 +1,113 @@ +class Aluno: + _nome = "" + _nota = 0 + def __init__(self, nome, nota) -> None: + self._nome = nome + self._nota = nota + def get_nota(self): + return self._nota + def get_nome(self): + return self._nome + pass + pass + +class Turma: + _matriculados = [] + _media = 0 + def add_aluno(self, aluno): + self._matriculados.append(aluno) + def set_nota_aprovacao(self, nota): + self._media = nota + def get_nota_aprovacao(self): + return self._media + def get_alunos(self) -> list: + return self._matriculados + def get_qtd_alunos(self) -> int: + return len(self._matriculados) + pass + +class CalculadoraDeNotas: + def __init__(self, turma: Turma) -> None: + self.turma = turma + pass + def get_media(self): + qtd_alunos = len(self.matriculados) + soma = 0 + for aluno in self.matriculados: + soma += aluno.get_nota() + return 0 if qtd_alunos == 0 else (soma / qtd_alunos) + def get_maior_nota(self): + aluno_nota_alta = None + for aluno in self.turma.get_alunos(): + if not aluno_nota_alta: + aluno_nota_alta = aluno + if aluno_nota_alta.get_nota() < aluno.get_nota(): + aluno_nota_alta = aluno + return aluno_nota_alta.get_nota() + pass + def get_menor_nota(self): + aluno_nota_baixa = None + for aluno in self.turma.get_alunos(): + if not aluno_nota_baixa: + aluno_nota_baixa = aluno + if aluno_nota_baixa.get_nota() > aluno.get_nota(): + aluno_nota_baixa = aluno + return aluno_nota_baixa.get_nota() + pass + def get_aprovados(self): + lista_resultado = [] + for aluno in self.turma.get_alunos(): + if aluno.get_nota() >= self.media: + lista_resultado.append(aluno) + return lista_resultado + pass + def get_reprovados(self): + lista_resultado = [] + for aluno in self.turma.get_alunos(): + if aluno.get_nota() < self.media: + lista_resultado.append(aluno) + return lista_resultado + pass + def get_notas_alpha(self): + lista_resultado = [] + for aluno in self.turma.get_alunos(): + lista_resultado.append( + aluno.get_nome(), + self.converte_nota(aluno.get_nota()) + ) + return lista_resultado + pass + def converte_nota(self, nota): + if nota == 10: + return "A+" + elif 9 <= nota < 10: + return "A" + elif 7 <= nota < 9: + return "B" + elif 5 <= nota < 7: + return "C" + elif 3 <= nota < 5: + return "D" + elif 1 <= nota < 3: + return "E" + elif 0 <= nota < 1: + return "F" + pass + pass + +""" +CALCULADORA DE NOTAS +==================== +1. Recebe uma turma, composta por uma lista de Alunos(nome, nota) e média para aprovar um aluno. +2. Calcula a média das notas da turma (get_media). +3. Qual a maior e menor nota (get_maior_nota, get_menor_nota). +4. Retorna alunos aprovados e reprovados (get_aprovados, get_reprovados). +5. Retorna lista de notas em representação de "letra". + - nota == 10 => "A+" + - 9 <= nota < 10 => "A" + - 7 <= nota < 9 => "B" + - 5 <= nota < 7 => "C" + - 3 <= nota < 5 => "D" + - 1 <= nota < 3 => "E" + - 0 <= nota < 1 => "F +""" diff --git "a/mod-13/exerc\303\255cios/test_calculadora_notas.py" "b/mod-13/exerc\303\255cios/test_calculadora_notas.py" new file mode 100644 index 0000000..af62ced --- /dev/null +++ "b/mod-13/exerc\303\255cios/test_calculadora_notas.py" @@ -0,0 +1,91 @@ +from calculadora_de_notas import Aluno, Turma, CalculadoraDeNotas +import unittest + +class TestAluno(unittest.TestCase): + def setUp(self) -> None: + self.aluno1 = Aluno("pedro", 7.5) + self.aluno2 = Aluno("victor", 9) + self.aluno3 = Aluno("cisco", 3) + self.aluno4 = Aluno("jonas", 0.5) + self.aluno5 = Aluno("brena", 10) + self.aluno6 = Aluno("livia", 9.5) + def test_retorna_nome(self): + self.assertEqual(self.aluno1.get_nome(), "pedro") + self.assertEqual(self.aluno5.get_nome(), "brena") + self.assertEqual(self.aluno6.get_nome(), "livia") + def test_retorna_nota(self): + self.assertEqual(self.aluno2.get_nota(), 9) + self.assertEqual(self.aluno3.get_nota(), 3) + self.assertEqual(self.aluno4.get_nota(), 0.5) + pass +class TestTurmaAdicionaAluno(unittest.TestCase): + def setUp(self) -> None: + self.aluno1 = Aluno("pedro", 7.5) + self.aluno2 = Aluno("victor", 9) + self.aluno3 = Aluno("cisco", 3) + self.aluno4 = Aluno("jonas", 0.5) + self.turma1 = Turma() + def test_adiciona_aluno_turma(self): + self.assertEqual(self.turma1.get_qtd_alunos(), 0) + self.turma1.add_aluno(self.aluno1) + self.assertEqual(self.turma1.get_qtd_alunos(), 1) + self.turma1.add_aluno(self.aluno2) + self.assertEqual(self.turma1.get_qtd_alunos(), 2) + self.turma1.add_aluno(self.aluno3) + self.assertEqual(self.turma1.get_qtd_alunos(), 3) + self.turma1.add_aluno(self.aluno4) + self.assertEqual(self.turma1.get_qtd_alunos(), 4) + self.assertIn(self.aluno3, self.turma1.get_alunos()) + self.assertIn(self.aluno2, self.turma1.get_alunos()) + +class TestTurmaNotaAprovacao(unittest.TestCase): + def setUp(self) -> None: + self.aluno1 = Aluno("pedro", 7.5) + self.aluno2 = Aluno("victor", 9) + self.turma2 = Turma() + def test_define_nota_aprova(self): + self.assertLessEqual( + self.turma2.get_nota_aprovacao(), + 10, + ) + self.turma2.set_nota_aprovacao(7) + self.assertLessEqual( + self.turma2.get_nota_aprovacao(), + 7, + ) + self.turma2.set_nota_aprovacao(5) + self.assertLessEqual( + self.turma2.get_nota_aprovacao(), + 6, + ) + self.turma2.set_nota_aprovacao(9) + self.assertGreaterEqual( + self.turma2.get_nota_aprovacao(), + 6, + ) + pass + +class TestTurmaRetornaAluno(unittest.TestCase): + def setUp(self) -> None: + self.aluno1 = Aluno("pedrito", 7.5) + self.aluno2 = Aluno("vilma", 9) + self.aluno3 = Aluno("francisco", 3) + self.aluno4 = Aluno("joana", 0.5) + self.aluno5 = Aluno("tiana", 8.5) + self.turma3 = Turma() + self.turma3.add_aluno(self.aluno1) + self.turma3.add_aluno(self.aluno2) + self.turma3.add_aluno(self.aluno3) + self.turma3.add_aluno(self.aluno4) + self.turma3.add_aluno(self.aluno5) + def test_verifica_alunos(self): + self.assertIn(self.aluno2, self.turma3.get_alunos()) + self.assertIn(self.aluno3, self.turma3.get_alunos()) + def test_quantidade_alunos(self): + for it in self.turma3.get_alunos(): + print(it.get_nome()) + self.assertEqual(self.turma3.get_qtd_alunos(), 4) + pass + pass + +unittest.main()