Category: Python

  • Modelos Avançados e Gerenciamento de Dados no Django

    Modelos Avançados e Gerenciamento de Dados no Django

    Quando trabalhamos com Django, uma das primeiras grandes “revelações” que temos é que os modelos são o coração do gerenciamento de dados. Se você nunca precisou lidar diretamente com SQL (e parabéns por isso!), é provável que ainda assim tenha criado e manipulado um modelo em Django sem sequer pensar duas vezes. É aqui que o “milagre” acontece: o ORM do Django traduz as suas definições de modelos Python em comandos SQL, permitindo que você trate os dados como objetos de forma quase mágica. Quase.

    Entretanto, à medida que sua aplicação cresce e suas necessidades de dados se tornam mais complexas, esse simples CRUD (Create, Read, Update, Delete) começa a parecer insuficiente. Modelos interligados por relacionamentos, consultas complexas, otimização de acesso a dados e gerenciamento de migrações se tornam desafios que não dá mais para evitar.

    Neste artigo, vamos dar uma olhada como trabalhar de forma avançada com modelos Django, cobrindo desde relacionamentos entre modelos até a criação de gerenciadores personalizados para consultas eficientes e o gerenciamento de migrações de banco de dados. Se você ainda acha que criar modelos é só adicionar models.Model e pronto, vamos além disso. E se você já teve medo de corromper seu banco de dados com uma migração malfeita, respire fundo e continue lendo.

    Trabalhando com relacionamentos entre modelos

    No Django, modelos não vivem isolados. Eles frequentemente se relacionam com outros modelos, criando uma rede de interdependências que espelha a estrutura de dados do seu aplicativo. Aqui, entra o famoso conceito dos relacionamentos entre tabelas, como OneToOne, ForeignKey, e ManyToMany. Cada um desses tipos de relacionamento tem um papel crucial, e é importante saber qual escolher para cada situação.

    Relacionamento OneToOne

    O relacionamento OneToOne é, como o nome sugere, uma conexão direta de um para um entre duas tabelas. É muito usado em casos onde você precisa expandir um modelo já existente sem modificar a tabela original. Um exemplo clássico é quando você precisa adicionar dados extras a um usuário, mas sem mexer na tabela User padrão do Django.

    from django.contrib.auth.models import User
    from django.db import models
    
    class Perfil(models.Model):
        user = models.OneToOneField(User, on_delete=models.CASCADE)
        bio = models.TextField()
        website = models.URLField()
    
        def __str__(self):
            return self.user.username
    Python

    Nesse exemplo, o modelo Perfil estende o modelo User. Cada instância de Perfil está ligada a exatamente um usuário, e vice-versa. Se o usuário for deletado, o perfil correspondente também será removido, graças ao parâmetro on_delete=models.CASCADE.

    Quando usar OneToOne:

    • Quando cada item de um modelo deve ter exatamente um correspondente em outro modelo.
    • Casos em que você precisa adicionar informações extras a uma tabela sem alterá-la diretamente (como estender o modelo User do Django).

    Relacionamento ForeignKey

    O relacionamento ForeignKey é o mais comum e cria uma relação de muitos para um. Ou seja, vários registros em uma tabela podem estar relacionados a um único registro em outra. Vamos ver um exemplo simples usando um blog.

    class Autor(models.Model):
        nome = models.CharField(max_length=100)
        email = models.EmailField()
    
        def __str__(self):
            return self.nome
    
    class Postagem(models.Model):
        titulo = models.CharField(max_length=200)
        conteudo = models.TextField()
        autor = models.ForeignKey(Autor, on_delete=models.CASCADE)
    
        def __str__(self):
            return self.titulo
    Python

    Aqui, cada Postagem está associada a um único Autor, mas um Autor pode ter várias Postagens. Novamente, o parâmetro on_delete=models.CASCADE garante que, se um autor for excluído, todas as suas postagens também sejam removidas.

    Quando usar ForeignKey:

    • Sempre que você tiver uma relação de muitos para um, como postagens de blog e autores, comentários e postagens, pedidos e clientes, etc.
    • Para garantir integridade referencial (opções como CASCADE e SET_NULL podem ser úteis, dependendo da necessidade de deletar ou manter registros órfãos).

    Relacionamento ManyToMany

    O relacionamento ManyToMany é usado quando ambos os lados de um relacionamento podem ter múltiplas ocorrências. Um exemplo clássico é o relacionamento entre alunos e cursos. Um aluno pode estar matriculado em vários cursos, e um curso pode ter muitos alunos.

    class Curso(models.Model):
        nome = models.CharField(max_length=200)
        descricao = models.TextField()
    
        def __str__(self):
            return self.nome
    
    class Aluno(models.Model):
        nome = models.CharField(max_length=100)
        cursos = models.ManyToManyField(Curso)
    
        def __str__(self):
            return self.nome
    Python

    Aqui, um Aluno pode estar matriculado em vários cursos, e um Curso pode ter muitos alunos. Django, nos bastidores, cria uma tabela intermediária para gerenciar esse relacionamento, poupando você de ter que definir manualmente essa estrutura.

    Qual melhor momento para usar ManyToMany:

    • Quando ambos os lados do relacionamento podem ter múltiplos vínculos, como alunos e cursos, tags e postagens, produtos e categorias, etc.
    • Ou quando você deseja que o Django crie e gerencie automaticamente as tabelas intermediárias.

    Gerenciadores personalizados em Django

    Em projetos maiores, onde as consultas de banco de dados se tornam mais complexas, os gerenciadores personalizados se tornam uma ferramenta essencial para manter o código limpo e reutilizável. O gerenciador padrão do Django é o objects, mas às vezes você precisa de algo mais específico, como consultar apenas registros ativos, criar métodos que façam agregações, ou até otimizar a quantidade de queries SQL geradas.

    O que são gerenciadores personalizados?

    Gerenciadores personalizados são classes que permitem modificar ou estender o comportamento padrão das consultas SQL. Por exemplo, se você tiver um modelo que contém um campo booleano ativo, e você só quiser listar os objetos onde ativo=True, você pode criar um gerenciador que automatize essa consulta.

    class AtivoManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(ativo=True)
    
    class Produto(models.Model):
        nome = models.CharField(max_length=100)
        preco = models.DecimalField(max_digits=10, decimal_places=2)
        ativo = models.BooleanField(default=True)
    
        objects = models.Manager()  # <-- Gerenciador padrão
        ativos = AtivoManager()  # <-- Gerenciador personalizado
    
        def __str__(self):
            return self.nome
    Python

    Aqui, temos dois gerenciadores: o objects, que retorna todos os produtos, e o ativos, que retorna apenas os produtos onde ativo=True. Usar o ativos facilita consultas sem precisar reescrever filtros repetidamente.

    # Todos os produtos
    produtos = Produto.objects.all()
    
    # Apenas produtos ativos
    produtos_ativos = Produto.ativos.all()
    Python

    Quando usar gerenciadores personalizados?

    Com certeza você deve ter se perguntado isso 😅

    Gerenciadores personalizados são úteis quando você tem filtros ou lógicas comuns que precisam ser aplicados consistentemente em todo o seu projeto. Eles ajudam a centralizar essa lógica, em vez de espalhar condições repetitivas pelo código.

    • Filtragem automática de registros: Como visto no exemplo anterior, para gerenciar estados como “ativos” ou “inativos”.
    • Consultas complexas: Quando você precisa aplicar agregações, juntar tabelas ou realizar operações mais sofisticadas.
    • Otimização de consultas: Evitar consultas repetitivas ou ineficientes, utilizando prefetching ou seleções específicas de campos.

    Migrações de banco de dados

    Nenhum projeto Django está completo sem lidar com migrações de banco de dados. Afinal, à medida que seu projeto evolui, seus modelos mudam — e, consequentemente, suas tabelas no banco de dados também precisam mudar. As migrações do Django facilitam essa transição, permitindo que você sincronize seu banco de dados com suas mudanças de código.

    O que são migrações?

    Migrações são arquivos gerados pelo Django que contêm instruções para o banco de dados sobre como criar, modificar ou deletar tabelas e colunas. Sempre que você altera um modelo (adiciona um campo, remove um relacionamento, etc.), você precisa gerar uma migração correspondente que “comunica” ao banco de dados como ele deve se ajustar a essas mudanças.

    Por exemplo, se você adicionar um novo campo descricao ao modelo Produto, você precisará criar uma migração correspondente:

    python manage.py makemigrations
    Python

    Esse comando analisa as mudanças nos modelos e cria um arquivo de migração, que pode ser aplicado ao banco de dados com:

    python manage.py migrate
    Python

    Migrações automáticas vs. manuais

    Em muitos casos, o Django é capaz de gerar migrações automaticamente com base nas suas mudanças de modelo. No entanto, há situações em que as migrações automáticas podem não ser suficientes ou podem gerar comportamentos inesperados. Nesses casos, você pode editar manualmente os arquivos de migração para garantir que a transição ocorra conforme o esperado.

    Exemplo de uma migração automática para adicionar um campo:

    class Migration(migrations.Migration):
    
        dependencies = [
            ('app_name', '0001_initial'),
        ]
    
        operations = [
            migrations.AddField(
                model_name='produto',
                name='descricao',
                field=models.TextField(default=''),
            ),
        ]
    Python

    Problemas comuns em migrações

    Embora o sistema de migrações do Django seja bastante robusto, alguns problemas podem surgir, como conflitos de migração (quando duas ou mais migrações tentam modificar a mesma coisa) ou erros ao tentar aplicar migrações a tabelas que já contêm dados.

    Dicas para lidar com problemas comuns:

    • Revertendo migrações: Se algo der errado, você pode reverter uma migração com python manage.py migrate app_name .
    • Migrações squashed: Em projetos grandes com muitas migrações, você pode “esmagar” várias migrações antigas em uma única migração para melhorar a eficiência.

    Práticas recomendadas para gerenciamento de banco de dados em Django

    Gerenciar um banco de dados eficientemente é essencial para garantir o bom desempenho da sua aplicação Django, especialmente à medida que ela cresce e passa a lidar com grandes volumes de dados. Abaixo, apresentamos algumas práticas recomendadas que você pode aplicar para otimizar consultas, manter a integridade dos dados e garantir que o seu banco de dados continue escalável à medida que sua aplicação evolui.

    Índices de banco de dados

    Uma das maneiras mais eficientes de melhorar a performance de consultas frequentes é usar índices no banco de dados. Um índice funciona como um índice de um livro, facilitando a busca de dados específicos sem a necessidade de varrer toda a tabela.

    No Django, você pode adicionar índices usando o parâmetro db_index=True nos campos:

    class Produto(models.Model):
        nome = models.CharField(max_length=100, db_index=True)
        preco = models.DecimalField(max_digits=10, decimal_places=2)
    Python

    Isso é especialmente útil para campos que são frequentemente filtrados ou ordenados, como IDs, datas, ou campos de busca. No entanto, deve-se usar índices com moderação, pois, embora acelerem a leitura, podem impactar a performance de escrita, já que o banco precisa atualizar os índices sempre que um registro é alterado ou inserido.

    Evitar o problema N+1

    O problema N+1 acontece quando o Django faz consultas separadas para cada item em uma relação ao invés de fazer uma única consulta otimizada. Isso pode ocorrer com ForeignKey ou ManyToMany, gerando um número excessivo de consultas ao banco de dados.

    Para evitar isso, é importante usar os métodos select_related e prefetch_related. O select_related faz um join SQL e traz os dados relacionados em uma única consulta. Já o prefetch_related carrega os dados relacionados em consultas separadas, mas de maneira eficiente, lidando bem com relacionamentos ManyToMany.

    Exemplo com select_related:

    # Sem select_related (potencial problema de N+1)
    produtos = Produto.objects.all()
    for produto in produtos:
        print(produto.categoria.nome)  # Gera uma consulta SQL para cada produto
    
    # Com select_related (join SQL em uma única consulta)
    produtos = Produto.objects.select_related('categoria').all()
    for produto in produtos:
        print(produto.categoria.nome)
    Python

    Exemplo com prefetch_related para ManyToMany:

    alunos = Aluno.objects.prefetch_related('cursos').all()
    for aluno in alunos:
        print(aluno.cursos.all())  # Carrega cursos relacionados em uma única consulta
    Python

    Isso reduz drasticamente a quantidade de consultas ao banco de dados, melhorando a performance.

    Manter consultas simples e específicas

    Consultas SQL complexas podem se tornar um gargalo significativo em aplicações maiores. Sempre que possível, mantenha suas consultas simples e diretas. Use agregações e filtros somente quando necessário e prefira trazer apenas os campos que você realmente precisa, ao invés de usar o all().

    Se você precisar de apenas alguns campos, use o método only() ou defer() para carregar apenas os dados essenciais:

    # Carrega apenas os campos 'nome' e 'preco'
    produtos = Produto.objects.only('nome', 'preco')
    Python

    Isso ajuda a reduzir o tempo de resposta e a memória utilizada, especialmente em tabelas com muitos campos.

    Cuidado com migrações destrutivas

    Quando o banco de dados já está em produção, alterações destrutivas — como remover colunas ou renomear tabelas — podem causar problemas graves, especialmente se houver muitos dados em jogo. Por isso, é recomendável que qualquer alteração potencialmente destrutiva seja cuidadosamente planejada.

    Dicas para lidar com migrações destrutivas:

    • Use migrações em fases: Quando possível, execute migrações que envolvem a adição de novos campos e somente depois remova ou altere os campos antigos.
    • Evite downtime: Em sistemas críticos, aplicar uma migração sem parar a aplicação pode ser crucial. Use estratégias de migrações zero-downtime, como adicionar novos campos em uma migração, copiar os dados de forma assíncrona, e só depois remover os campos antigos.

    Otimização de escritas com bulk_create e bulk_update

    Ao inserir ou atualizar muitos registros de uma vez, o uso de bulk_create e bulk_update pode otimizar muito o tempo de execução, evitando que o banco de dados seja acessado repetidamente.

    Exemplo com bulk_create:

    pythonCopiar códigoprodutos = [
        Produto(nome='Produto A', preco=50),
        Produto(nome='Produto B', preco=100),
        Produto(nome='Produto C', preco=150),
    ]
    Produto.objects.bulk_create(produtos)
    Python

    Aqui, o Django fará apenas uma única consulta SQL para inserir todos os produtos, em vez de fazer uma consulta separada para cada produto. O mesmo princípio se aplica ao bulk_update para atualizações em massa.

    Backup e versionamento do banco de dados

    Independentemente do tamanho da sua aplicação, é importante garantir que você tenha backups regulares e versionamento adequado do banco de dados, especialmente antes de aplicar grandes mudanças ou migrações.

    Algumas dicas:

    • Backups automáticos: Configure backups automáticos para que, em caso de falha, você possa restaurar o banco de dados rapidamente.
    • Versionamento de esquema: Use ferramentas como o django-dbbackup ou scripts manuais para manter o controle das versões do banco de dados, principalmente quando ele passa por grandes mudanças.

    Conclusão

    Neste artigo, exploramos os conceitos essenciais para um gerenciamento eficiente de banco de dados em Django, desde os relacionamentos entre modelos até gerenciadores personalizados e migrações. Compreender como esses elementos impactam o desempenho e a organização da aplicação é fundamental para criar projetos escaláveis e bem estruturados.

    Vimos que escolher o tipo certo de relacionamento, como OneToOne, ForeignKey ou ManyToMany, pode melhorar a eficiência das consultas e manter a integridade dos dados. Além disso, gerenciadores personalizados ajudam a centralizar consultas complexas, otimizando o código e o desempenho. Quanto às migrações, o planejamento cuidadoso é essencial para garantir que mudanças no banco de dados sejam seguras e sem problemas em produção.

    Por fim, a adoção de boas práticas — como o uso adequado de índices, a prevenção de consultas N+1, e a simplificação de consultas — garante que sua aplicação Django seja rápida e sustentável à medida que cresce. Gerenciar bem um banco de dados não é só sobre armazenar informações, mas também sobre garantir que o acesso a esses dados seja eficiente e seguro.

  • CBV vs FBV no Django: Quando Usar Cada Uma

    CBV vs FBV no Django: Quando Usar Cada Uma

    Quando começamos a desenvolver uma aplicação em Django, é comum nos depararmos com uma escolha aparentemente simples: usar visualizações baseadas em função (Function-Based Views, FBVs) ou visualizações baseadas em classe (Class-Based Views, CBVs). Para muitos desenvolvedores iniciantes, essa decisão pode parecer trivial, mas ela pode ter implicações significativas no longo prazo, à medida que a complexidade do projeto aumenta.

    As FBVs são, em essência, uma função Python que processa uma requisição e retorna uma resposta. É um modelo mais direto e sem muitos segredos, algo que agrada muito quem está começando. No entanto, à medida que as aplicações se tornam mais complexas e a lógica de visualizações começa a se repetir em várias partes do código, manter tudo dentro de funções simples pode se tornar uma tarefa árdua. Aqui é onde as CBVs entram em cena, oferecendo uma abordagem mais estruturada, baseada em classes e orientada a objetos.

    Mas por que isso é importante? Simples: a escolha entre FBV e CBV pode impactar diretamente a manutenibilidade, reutilização de código, e até a performance da sua aplicação. Imagine que você esteja desenvolvendo um projeto com dezenas ou centenas de endpoints diferentes, muitos dos quais têm lógica semelhante, mas com pequenas variações. Organizar todo esse código sem repetir lógica pode ser um desafio considerável com FBVs.

    Agora, é importante lembrar que o Django não nasceu ontem. O uso de CBVs é um recurso relativamente “recente”, enquanto as FBVs são o método original desde as primeiras versões. Portanto, se você tem um colega mais experiente que insiste em usar FBVs, é provável que ele tenha suas razões — seja uma questão de estilo pessoal ou preferência pela simplicidade de “controlar tudo à mão”.

    Mas antes de fazer essa escolha, é essencial entender as diferenças práticas entre esses dois modelos, seus prós e contras e, o mais importante, quando cada um faz mais sentido no contexto da sua aplicação.

    O que são visualizações baseadas em função (FBVs)?

    Vamos começar pelo básico. Uma visualização baseada em função é literalmente uma função Python que recebe um objeto request e retorna uma resposta HTTP. Isso é tão direto quanto parece. A simplicidade das FBVs é uma de suas maiores vantagens, especialmente para desenvolvedores que ainda não estão familiarizados com conceitos de programação orientada a objetos (POO).

    Aqui está um exemplo bem básico de uma FBV:

    from django.http import HttpResponse
    
    def minha_view(request):
        return HttpResponse("Olá, mundo!")
    Bash

    Esta view faz apenas uma coisa: retorna “Olá, mundo!” como resposta ao receber uma requisição HTTP. Parece um “Hello World” de outro framework? Sim, e essa é a beleza da simplicidade das FBVs. No entanto, como qualquer desenvolvedor mais experiente sabe, aplicações reais são bem mais complicadas do que isso.

    Cenários práticos para FBVs

    As FBVs brilham em cenários onde a lógica de negócio é simples e não há necessidade de reutilização massiva de código entre múltiplas visualizações. Vamos considerar uma aplicação que calcula a média de notas de alunos:

    from django.http import JsonResponse
    
    def calcular_media(request):
        notas = request.GET.getlist('notas')
        try:
            notas = [float(nota) for nota in notas]
            media = sum(notas) / len(notas)
        except ValueError:
            return JsonResponse({'error': 'Por favor, forneça apenas números válidos.'}, status=400)
        
        return JsonResponse({'media': media})
    Bash

    Aqui, a view faz uma operação relativamente simples: recebe uma lista de notas via parâmetros GET, calcula a média e retorna o resultado em formato JSON. Se algo der errado (como notas inválidas), uma mensagem de erro é retornada.

    Uso de decorators em FBVs

    A simplicidade das FBVs permite uma fácil customização utilizando decorators, que podem adicionar funcionalidades à função sem alterar sua lógica principal. Um uso comum de decorators em Django é para controle de acesso. Por exemplo, você pode garantir que uma view só seja acessada por usuários autenticados:

    from django.contrib.auth.decorators import login_required
    
    @login_required
    def dashboard(request):
        return HttpResponse("Bem-vindo ao seu dashboard!")
    Bash

    Aqui, o decorator @login_required verifica se o usuário está autenticado antes de permitir o acesso ao dashboard. Esse é um exemplo clássico de como as FBVs permitem o controle total da lógica de execução com um código simples.

    Vantagens das FBVs

    • Simplicidade e clareza: Como são funções simples, as FBVs são fáceis de entender e rápidas de escrever, sendo uma ótima escolha para protótipos ou aplicações pequenas.
    • Flexibilidade: Você tem controle total sobre o que acontece em cada requisição, o que pode ser uma vantagem em cenários onde você precisa de algo muito específico.
    • Menor overhead: Para views muito simples, as FBVs podem ser ligeiramente mais rápidas, já que não há overhead de herança ou resolução de métodos como nas CBVs.

    Desvantagens das FBVs

    • Escalabilidade: À medida que sua aplicação cresce e as visualizações ficam mais complexas, a organização do código em FBVs pode se tornar um pesadelo. Imagine ter que repetir a lógica de validação de autenticação em várias views sem uma maneira clara de reutilizar esse código.
    • Dificuldade em reutilizar lógica: Embora decorators possam ajudar, não há uma maneira natural de reutilizar pedaços de lógica em múltiplas views, o que pode levar a duplicação de código.

    O que são visualizações baseadas em classe (CBVs)?

    Agora que entendemos o que são FBVs, vamos mergulhar nas visualizações baseadas em classe. Diferentemente das FBVs, as CBVs utilizam conceitos da Programação Orientada a Objetos (POO). Em vez de funções, trabalhamos com classes que herdam de uma classe base, fornecida pelo Django, e implementam métodos para lidar com os diferentes tipos de requisição (GET, POST, PUT, etc.).

    Aqui está um exemplo básico de uma CBV:

    from django.http import HttpResponse
    from django.views import View
    
    class MinhaView(View):
        def get(self, request):
            return HttpResponse("Olá, mundo!")
    Bash

    Neste exemplo, MinhaView é uma classe que herda da classe View do Django. O método get é chamado quando a view recebe uma requisição HTTP GET. Assim como nas FBVs, o objetivo aqui é retornar “Olá, mundo!”, mas agora dentro da estrutura de uma classe.

    CBVs Genéricas

    O verdadeiro poder das CBVs vem das views genéricas, que o Django fornece para acelerar o desenvolvimento de aplicações comuns. Por exemplo, imagine que você queira criar uma página que exiba uma lista de objetos de um determinado modelo. Com FBVs, você teria que escrever a lógica para buscar os objetos do banco de dados, passá-los para o contexto e renderizar o template manualmente. Com CBVs genéricas, isso é muito mais fácil:

    from django.views.generic import ListView
    from .models import Aluno
    
    class ListaAlunosView(ListView):
        model = Aluno
        template_name = 'alunos/lista.html'
    Bash

    Neste exemplo, ListaAlunosView é uma CBV genérica que automaticamente busca todos os objetos do modelo Aluno, os insere no contexto e renderiza o template lista.html. Tudo isso sem que você precise escrever a lógica repetitiva de consulta ao banco de dados e renderização do template.

    Mixins em CBVs

    Uma das maiores vantagens das CBVs é a capacidade de reutilizar lógica por meio de mixins. Mixins são classes que você pode “misturar” em suas CBVs para adicionar funcionalidades específicas sem repetir código.

    Por exemplo, digamos que você queira garantir que apenas usuários autenticados possam acessar uma determinada view. Em vez de usar um decorator como fizemos nas FBVs, podemos usar o LoginRequiredMixin:

    from django.contrib.auth.mixins import LoginRequiredMixin
    from django.views.generic import TemplateView
    
    class DashboardView(LoginRequiredMixin, TemplateView):
        template_name = 'dashboard.html'
    Bash

    Aqui, LoginRequiredMixin faz com que a view só seja acessível para usuários autenticados. O uso de mixins permite que você adicione funcionalidades comuns a várias views sem precisar repetir código, tornando suas CBVs extremamente flexíveis e reutilizáveis.

    Vantagens das CBVs

    • Reuso de código: A herança de classes e o uso de mixins tornam as CBVs muito mais eficientes em termos de reutilização de lógica. Se você tem várias views que compartilham funcionalidades, as CBVs são a escolha ideal.
    • Organização: Ao dividir a lógica de cada tipo de requisição em métodos (get(), post(), etc.), o código se torna mais organizado e fácil de entender.
    • Extensibilidade: CBVs permitem que você crie hierarquias de classes, estenda funcionalidades e adicione comportamentos personalizados sem duplicar código.

    Desvantagens das CBVs

    • Curva de aprendizado: Para desenvolvedores iniciantes, a programação orientada a objetos pode ser mais difícil de entender, especialmente quando comparada à simplicidade das FBVs.
    • Abstração excessiva: Em alguns casos, as CBVs fazem muitas coisas “automáticas”, o que pode tornar o comportamento da aplicação mais difícil de entender e depurar.

    Diferenças práticas entre CBVs e FBVs

    Agora que já abordamos as definições e exemplos de visualizações baseadas em função (FBVs) e visualizações baseadas em classe (CBVs), chegou a hora de fazer uma comparação mais profunda entre as duas abordagens. Vamos explorar aspectos como performance, facilidade de uso, reutilização de código, e manutenibilidade para ajudar a determinar qual delas é mais adequada em diferentes situações.

    Clareza e Simplicidade

    Como vimos nos exemplos anteriores, as FBVs são incrivelmente diretas. O fluxo de código em uma FBV é linear: a função recebe uma requisição, executa uma lógica e retorna uma resposta. Se o seu projeto é pequeno e você está lidando com operações simples, essa abordagem pode ser a mais produtiva, pois não há muitas abstrações a serem compreendidas.

    Por exemplo, em uma view onde você só precisa retornar um JSON simples baseado em parâmetros de URL, as FBVs são uma solução rápida e fácil:

    from django.http import JsonResponse
    
    def calcular_soma(request):
        numeros = request.GET.getlist('numeros')
        soma = sum([int(num) for num in numeros])
        return JsonResponse({'soma': soma})
    Bash

    Não há necessidade de classes, herança, ou qualquer outro conceito adicional. O código está todo ali, e é fácil de seguir.

    Já as CBVs oferecem uma abordagem mais robusta e escalável, mas podem parecer complexas no início. O simples ato de criar uma classe, implementar métodos e seguir o padrão da POO já adiciona um nível extra de “peso cognitivo” ao código, o que pode ser um empecilho para novos desenvolvedores ou para quem está acostumado com uma abordagem mais funcional.

    from django.http import JsonResponse
    from django.views import View
    
    class CalcularSomaView(View):
        def get(self, request):
            numeros = request.GET.getlist('numeros')
            soma = sum([int(num) for num in numeros])
            return JsonResponse({'soma': soma})
    Bash

    Embora este exemplo com CBV pareça similar à FBV equivalente, o benefício da CBV fica evidente em cenários mais complexos, como quando você precisa de suporte para múltiplos tipos de requisição (GET, POST, etc.) ou quando a lógica da view precisa ser reutilizada em várias partes do código.

    Reutilização de Código

    Um dos pontos mais fortes das CBVs é a possibilidade de reutilizar código de maneira muito mais eficiente do que nas FBVs. Com a capacidade de herdar de classes e utilizar mixins, as CBVs permitem criar estruturas modulares e reutilizáveis, o que é particularmente útil em projetos de médio a grande porte.

    Por exemplo, se você tem várias views que exigem autenticação e realizam operações semelhantes, pode criar uma classe base que contenha toda a lógica comum e herdar essa classe nas suas views específicas. Isso economiza tempo e evita duplicação de código:

    from django.contrib.auth.mixins import LoginRequiredMixin
    from django.views.generic import View
    
    class BaseProtectedView(LoginRequiredMixin, View):
        def dispatch(self, request, *args, **kwargs):
            # Lógica comum de autenticação ou validação
            return super().dispatch(request, *args, **kwargs)
    
    class MinhaView(BaseProtectedView):
        def get(self, request):
            return HttpResponse("Acesso autorizado!")
    Bash

    Aqui, BaseProtectedView é uma classe base que impõe a verificação de autenticação e pode conter qualquer lógica comum às views protegidas. A view MinhaView herda toda essa funcionalidade sem precisar reescrevê-la. Com FBVs, essa abordagem seria mais complexa e provavelmente envolveria duplicação de código ou a necessidade de usar múltiplos decorators, o que nem sempre é ideal.

    As FBVs, por outro lado, não oferecem suporte nativo para esse tipo de reutilização. Se você precisar reutilizar lógica entre várias FBVs, terá que recorrer a soluções alternativas, como decorators ou funções auxiliares, o que pode acabar tornando o código menos legível.

    Organização e Extensibilidade

    A organização do código em CBVs é naturalmente mais estruturada, graças à separação clara entre diferentes tipos de requisição e à organização da lógica em métodos distintos. Quando você usa uma CBV, sabe exatamente onde encontrar a lógica de uma requisição GET, POST, etc., pois cada uma dessas ações será implementada em um método específico da classe.

    Exemplo de uma CBV que lida com múltiplos tipos de requisição:

    from django.http import JsonResponse
    from django.views import View
    
    class OperacoesView(View):
        def get(self, request):
            return JsonResponse({"message": "Requisição GET recebida"})
    
        def post(self, request):
            return JsonResponse({"message": "Requisição POST recebida"})
    
        def put(self, request):
            return JsonResponse({"message": "Requisição PUT recebida"})
    Bash

    Essa separação ajuda a manter o código limpo e mais fácil de manter, especialmente em projetos grandes, onde uma mesma view pode ter que lidar com diferentes tipos de requisição.

    Nas FBVs, por outro lado, toda a lógica para diferentes tipos de requisição precisaria ser tratada dentro da mesma função, o que pode rapidamente se tornar confuso. Um exemplo seria:

    def operacoes_view(request):
        if request.method == "GET":
            return JsonResponse({"message": "Requisição GET recebida"})
        elif request.method == "POST":
            return JsonResponse({"message": "Requisição POST recebida"})
        elif request.method == "PUT":
            return JsonResponse({"message": "Requisição PUT recebida"})
        else:
            return JsonResponse({"message": "Método não suportado"}, status=405)
    Bash

    Neste caso, o código pode ser mais difícil de seguir à medida que a complexidade aumenta. O fato de termos que lidar com todos os métodos HTTP em uma única função faz com que a organização do código se deteriore rapidamente conforme mais lógica é adicionada.

    Performance e Overhead

    Quando se fala em performance, as FBVs têm uma leve vantagem em termos de overhead. Como as FBVs são apenas funções, não há sobrecarga adicional de herança de classes, resolução de métodos e outras funcionalidades que o Django precisa gerenciar quando você usa CBVs.

    No entanto, para a maioria das aplicações modernas, essa diferença de performance é insignificante. A menos que você esteja lidando com um projeto de altíssima performance, como um sistema de tempo real com centenas de milhares de requisições simultâneas, a diferença entre CBVs e FBVs no quesito performance é praticamente imperceptível.

    Além disso, o ganho em reusabilidade, organização e manutenção que as CBVs proporcionam muitas vezes compensa o pequeno overhead adicional. O uso de CBVs em aplicações de médio e grande porte pode até melhorar a performance geral do projeto a longo prazo, ao evitar duplicação de código e promover uma melhor organização da lógica.

    Testabilidade e Debugging

    Quando se trata de testabilidade, as FBVs tendem a ser mais fáceis de testar, especialmente em casos simples. Como são apenas funções, você pode isolar a lógica com facilidade e escrever testes unitários sem ter que se preocupar com o estado da classe ou com herança.

    Exemplo de um teste simples de uma FBV:

    from django.test import TestCase
    from django.http import HttpRequest
    from .views import calcular_soma
    
    class TesteFBV(TestCase):
        def test_calcular_soma(self):
            request = HttpRequest()
            request.GET['numeros'] = ['1', '2', '3']
            response = calcular_soma(request)
            self.assertEqual(response.json()['soma'], 6)
    Bash

    Por outro lado, as CBVs exigem mais cuidado ao testar, pois você pode ter que lidar com a herança e o estado da classe em si. No entanto, a separação entre métodos (GET, POST, etc.) nas CBVs pode tornar o teste de cada parte da lógica individualmente mais fácil, já que cada método geralmente contém uma funcionalidade específica.

    Aqui está um exemplo de um teste para uma CBV:

    from django.test import TestCase
    from django.http import HttpRequest
    from .views import OperacoesView
    
    class TesteCBV(TestCase):
        def test_get(self):
            request = HttpRequest()
            request.method = 'GET'
            response = OperacoesView.as_view()(request)
            self.assertEqual(response.status_code, 200)
            self.assertEqual(response.json()['message'], "Requisição GET recebida")
    Bash

    Em relação ao debugging, as FBVs também podem ser mais fáceis de depurar devido à sua simplicidade. No entanto, as CBVs podem se tornar complexas quando múltiplas classes e mixins estão envolvidos, e entender o fluxo de execução pode exigir um conhecimento mais profundo de como o Django resolve as heranças e chamadas de métodos. Para resolver isso, o uso de ferramentas de depuração como o pdb ou django debug toolbar pode ser essencial.

    Quando usar CBVs ou FBVs?

    Chegamos à pergunta central deste artigo: Quando usar CBVs e quando usar FBVs? A resposta, como em muitas questões de desenvolvimento de software, é “depende”. Ambas as abordagens têm seus méritos e são adequadas para diferentes cenários.

    Quando optar pelas FBVs?

    • Simplicidade é essencial: Se você está desenvolvendo uma aplicação simples, onde as visualizações não precisam de muita lógica de reutilização e herança, as FBVs podem ser a escolha mais prática.
    • Prototipagem rápida: Para projetos pequenos ou protótipos, onde você precisa de resultados rápidos, as FBVs podem ser mais fáceis de implementar e depurar.
    • Pequenas operações: Se suas visualizações estão limitadas a executar operações muito específicas e não envolvem uma lógica complexa que precise ser reutilizada, as FBVs podem ser mais adequadas.

    Quando optar pelas CBVs?

    • Aplicações complexas: Se você está trabalhando em uma aplicação de médio a grande porte, onde a modularidade, reutilização de código e organização são essenciais, as CBVs são uma escolha melhor.
    • Reutilização de lógica: Se várias visualizações compartilham partes significativas de lógica (como validação, autenticação, etc.), as CBVs são ideais, pois permitem a criação de classes base e o uso de mixins.
    • Manutenção a longo prazo: Se o seu projeto vai crescer e ser mantido por um longo período, o uso de CBVs pode facilitar a manutenibilidade, especialmente em equipes grandes, onde a clareza e a organização são críticas.

    Conclusão

    As visualizações baseadas em função (FBVs) e as visualizações baseadas em classe (CBVs) têm suas vantagens e desvantagens. A escolha entre uma ou outra depende do contexto do projeto, das necessidades de reutilização de código, da complexidade da lógica da view e da sua familiaridade com POO.

    Para projetos pequenos e simples, onde a lógica de visualização é clara e não precisa ser reutilizada, as FBVs são uma solução direta e eficaz. No entanto, em projetos maiores ou em crescimento, as CBVs oferecem uma estrutura mais organizada e reutilizável, permitindo uma manutenção mais eficiente e a criação de visualizações modulares.

    Em última análise, o importante é lembrar que não há uma escolha “correta” entre FBVs e CBVs — há apenas a escolha certa para o seu projeto e para o seu contexto.

    Então, ao se deparar com a famosa pergunta “FBV ou CBV?”, agora você tem a base necessária para responder de forma mais confiante: “Depende do contexto!”


    Bônus: Explorando Class-Based Views com Classy CBV

    Se você está trabalhando com visualizações baseadas em classe (CBVs) no Django, o site Classy Class-Based Views (CCBV) é uma ferramenta indispensável. Ele organiza de forma clara todas as CBVs do Django, mostrando suas heranças, métodos, e como cada uma delas pode ser usada e personalizada.

    Com o CCBV, você pode:

    • Entender rapidamente a hierarquia de herança: Veja como as CBVs genéricas são estruturadas e quais métodos você pode sobrescrever.
    • Explorar métodos e funcionalidades: O site detalha quais métodos cada CBV oferece, ajudando você a encontrar a melhor forma de personalizar suas views sem perder tempo.
    • Facilitar a customização: Se você quer ajustar o comportamento de uma ListView, por exemplo, o CCBV mostra exatamente onde e como você pode fazer isso, como sobrescrever o método get_queryset() para filtrar dados.

    Ao invés de vasculhar a documentação oficial ou o código-fonte do Django, o CCBV te dá uma visão prática e rápida para melhorar sua produtividade e confiança no desenvolvimento com CBVs. Se você ainda não conhece, vale a pena visitar: Classy CBV.

  • Formulários no Django: Manipulação, Validação e Renderização

    Formulários no Django: Manipulação, Validação e Renderização

    Formulários no Django são uma parte essencial de qualquer aplicação web que precise interagir com o usuário. No Django, o sistema de formulários é um dos recursos mais poderosos e flexíveis, facilitando o trabalho com dados de entrada, sua validação e posterior manipulação.

    Se você já precisou lidar com formulários HTML manualmente, sabe o quão trabalhoso pode ser garantir que todos os dados sejam capturados e validados corretamente.

    É aí que entra o Django, automatizando grande parte desse processo e permitindo que você foque no desenvolvimento da lógica da sua aplicação.

    Esta postagem explora a manipulação de formulários no Django, incluindo a criação, validação e renderização, com exemplos práticos para ilustrar cada etapa.

    Criando um Formulário no Django

    Django fornece uma classe chamada forms.Form, que facilita a criação e manipulação de formulários. Além disso, o Django oferece o forms.ModelForm, que automaticamente gera um formulário baseado em um modelo (Model) definido no banco de dados. Comecemos pela criação de um formulário simples usando forms.Form.

    Exemplo básico de criação de formulário

    from django import forms
    
    class ContatoForm(forms.Form):
        nome = forms.CharField(label='Nome', max_length=100)
        email = forms.EmailField(label='E-mail')
        mensagem = forms.CharField(widget=forms.Textarea, label='Mensagem')
    
    Python

    No exemplo acima, definimos um formulário de contato com três campos:

    • nome: Um campo de texto simples (usando CharField) com um limite de 100 caracteres.
    • email: Um campo de e-mail que automaticamente valida se o dado inserido é um endereço de e-mail válido.
    • mensagem: Um campo de texto maior, onde usamos forms.Textarea para renderizar um
      class ContatoForm(forms.Form):
          nome = forms.CharField(label='Nome', max_length=100, widget=forms.TextInput(attrs={'class': 'form-control'}))
          email = forms.EmailField(label='E-mail', widget=forms.EmailInput(attrs={'class': 'form-control'}))
          mensagem = forms.CharField(widget=forms.Textarea(attrs={'rows': 5, 'class': 'form-control'}), label='Mensagem')
      
      Python

    Aqui usamos o argumento attrs para adicionar classes CSS personalizadas a cada campo, que seriam úteis ao integrar com frameworks como Bootstrap, por exemplo.

    Em outras palavras, os widgets te da a oportunidade o que você poderá adicionar dentro dos inputs que serão renderizados no HTML.

    Tipos de campos no Formulários no Django

    Django oferece uma grande variedade de campos para formulários, cada um com uma função específica. Alguns dos mais usados incluem:

    • CharField: Usado para entradas de texto simples.
    • EmailField: Valida se o valor inserido é um e-mail válido.
    • IntegerField: Valida se o valor inserido é um número inteiro.
    • DateField: Para campos de data.
    • BooleanField: Um checkbox booleano.

    Exemplo de um formulário com diferentes tipos de campo:

    class RegistroForm(forms.Form):
        nome = forms.CharField(label='Nome', max_length=100)
        idade = forms.IntegerField(label='Idade')
        data_nascimento = forms.DateField(label='Data de Nascimento')
        aceita_termos = forms.BooleanField(label='Aceito os termos e condições')
    Python

    Caso você viu a ultima postagem que fiz sobre models você perceberá que os campos de formulários do Django são parecidos em termos de “tipagem”. Exatamente, como nem sempre usaremos formulários para fazer inserção de dados para o banco de dados e melhor ter forms e models separados, embora sejam parecidos. 😉

    Validação de Formulários

    Django oferece validação automática de dados para os tipos de campo. No entanto, existem cenários onde você precisará implementar validações personalizadas para os seus formulários. A validação ocorre em dois níveis:

    1. Validação embutida: Django já inclui regras de validação padrão para muitos tipos de campos (por exemplo, EmailField verifica se o valor inserido é um e-mail válido).
    2. Validação personalizada: Você pode criar suas próprias regras de validação para campos específicos.

    Validação embutida nos formulários no Django

    Sempre que você utiliza um tipo de campo como EmailField, IntegerField, etc., o Django automaticamente aplica validações apropriadas ao valor recebido.

    Por exemplo, se tentarmos enviar um valor inválido para o campo de e-mail no formulário de contato que criamos acima, Django nos retornará um erro de validação:

    form = ContatoForm({'nome': 'João', 'email': 'emailinvalido', 'mensagem': 'Olá!'})
    if form.is_valid():
        # Este bloco não será executado
        print("Formulário válido")
    else:
        print(form.errors)
    
    Python

    Aqui, como o e-mail é inválido, o Django vai gerar um erro como parte do dicionário form.errors que poderá ser exibido no template.

    Validação personalizada nos formulários no Django

    Além da validação embutida, você pode definir suas próprias regras de validação para campos individuais. Isso é feito através do método clean_(), onde você pode especificar a lógica de validação adicional para um determinado campo.

    Vamos criar um exemplo onde validamos o nome de usuário para garantir que ele tenha pelo menos 5 caracteres:

    class RegistroForm(forms.Form):
        nome = forms.CharField(label='Nome', max_length=100)
        email = forms.EmailField(label='E-mail')
    
        def clean_nome(self): # <-- Aqui você esta adicionando validação ao campo "nome" 😉 
            nome = self.cleaned_data.get('nome')
            if len(nome) < 5:
                raise forms.ValidationError("O nome deve ter pelo menos 5 caracteres.")
            return nome
    
    Python

    Aqui, o método clean_nome será executado automaticamente durante o processo de validação do formulário. Se o nome for menor que 5 caracteres, Django gerará um erro de validação.

    https://wordpress.vps9144.panel.icontainer.cloud/introducao-ao-framework-django-compreendendo-o-framework-e-sua-arquitetura/#comments

    Validação geral de formulário

    Além da validação de campos individuais, você também pode realizar validações no nível do formulário. Isso é feito sobrescrevendo o método clean() da classe do formulário “Form”. Isso é útil quando você precisa validar dois ou mais campos em conjunto.

    Exemplo de validação no nível do formulário:

    class RegistroForm(forms.Form):
        senha = forms.CharField(widget=forms.PasswordInput)
        confirma_senha = forms.CharField(widget=forms.PasswordInput)
    
        def clean(self):
            cleaned_data = super().clean()
            senha = cleaned_data.get("senha")
            confirma_senha = cleaned_data.get("confirma_senha")
    
            if senha and confirma_senha and senha != confirma_senha:
                raise forms.ValidationError("As senhas não coincidem.")
    
    Python

    Neste exemplo, garantimos que os campos senha e confirma_senha correspondam. Se não forem iguais, um erro de validação será gerado.

    Renderizando Formulários no Django

    Uma vez que criamos e validamos um formulário, o próximo passo é renderizá-lo em um template HTML. No Django, isso pode ser feito de forma bastante simples usando o objeto form que é passado para o template a partir da view.

    Exemplo básico de renderização de formulário

    No arquivo views.py, passamos uma instância do formulário para o contexto:

    from django.shortcuts import render
    from .forms import ContatoForm
    
    def contato_view(request):
        form = ContatoForm()
        return render(request, 'contato.html', {'form': form})
    Python

    No template contato.html, podemos renderizar o formulário de diferentes maneiras. A forma mais simples é usando {{ form.as_p }}, que renderiza cada campo como um parágrafo (

    ):

    <form method="post">
        {% csrf_token %}
        {{ form.as_p }} <-- Aqui todas os campos serão adicionados. 
        <button type="submit">Enviarbutton>
    form>
    HTML

    Você também pode renderizar manualmente cada campo do formulário, o que oferece mais controle sobre o HTML gerado:

    <form method="post">
        {% csrf_token %}
        <div>
            {{ form.nome.label_tag }}
            {{ form.nome }}
            {{ form.nome.errors }}
        div>
        <div>
            {{ form.email.label_tag }}
            {{ form.email }}
            {{ form.email.errors }}
        div>
        <div>
            {{ form.mensagem.label_tag }}
            {{ form.mensagem }}
            {{ form.mensagem.errors }}
        div>
        <button type="submit">Enviarbutton>
    form>
    HTML

    Ao renderizar cada campo manualmente, você também pode exibir os erros de validação associados diretamente ao lado de cada campo, como mostrado acima com {{ form.campo.errors }}.

    Fluxograma Explicando Os Passos Do Formulário No Django

    Conclusão

    Formulários no Django são uma ferramenta poderosa para lidar com dados de entrada de usuários, validação e renderização em HTML.

    Neste post, você aprendeu como criar formulários, validar dados tanto de forma embutida quanto personalizada, e finalmente renderizar o formulário no template HTML. Dominar esse recurso do Django simplifica a coleta de dados em sua aplicação, além de garantir que os dados sejam válidos e seguros.

  • Como Criar Um Pacote Django Privado

    Como Criar Um Pacote Django Privado

    Neste material, detalharei como você pode criar seu próprio pacote Django privado para ser reutilizado entre diferentes projetos.

    Portanto, para acompanhar, usaremos um aplicativo chamado cart que tem a função de manipular pedidos personalizados enviando-os para checkout. Este aplicativo será transformado em um pacote para ser usado por outros projetos Django, onde todos os passos serão explicados para você.

    Diretorio Inicial

    seu_pacote_django/
        └───cart/
            │   admin.py
            │   apps.py
            │   contexts.py
            │   models.py
            │   urls.py
            │   views.py
            │   __init__.py
            │   
            ├───migrations/
            │       __init__.py
            │       
            ├───templates/
            │       cart.html
            │       header2.html
            │
            └───tests/
                    test_urls.py
                    test_views.py
                    __init__.py
    Bash

    Como você pode ver, o diretório inicial tem apenas o aplicativo do carrinho dentro dele. Portanto, para iniciar seu pacote, você precisará criar mais arquivos que lidarão com o processo de construção do pacote, bem como alguns requisitos que você precisará caso, algum dia, queira torná-lo público, talvez adicionando-o ao PYPI.org.

    Arquivos Importantes Para Construir o Pacote Django:

    Nesta seção serão detalhados os arquivos necessários para construir o pacote do carrinho. Portanto, para facilitar o acompanhamento, a instrução será seguida como nome do arquivo + instrução + código.

    1. Arquivo Setup.py

    Este é o arquivo mais importante. setup.py representa main quando você chama as funções de instalação. Basicamente, dentro do setup.py você deve adicionar todas as informações necessárias para criar seu pacote. Como o nome do pacote, versão, licença e etc:

    # setup.py
    
    import os
    from setuptools import find_packages, setup
    
    with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme:
        README = readme.read()
    
    # allow setup.py to be run from any path
    os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
    
    setup(
        name='cart',
        version='0.0.1',
        packages=find_packages(),
        include_package_data=True,
        license='Your license', 
        description='A cart package that handles payments with stripe.',
        long_description=README,
        url='yoursite.com',
        author='you',
        author_email='your@email.com',
        classifiers=[
            'Environment :: Web Environment',
            'Framework :: Django',
            'Framework :: Django :: 3.2',  
            'Intended Audience :: For my own or company usage',
            'License :: OSI Approved :: Your License',  
            'Operating System :: OS Independent',
            'Programming Language :: Python',
            'Programming Language :: Python :: 3',
            'Programming Language :: Python :: 3.6',
            'Programming Language :: Python :: 3.8',
            'Programming Language :: Python :: 3.9',
            'Topic :: Internet :: WWW/HTTP',
            'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
        ],
    )
    Python

    Existem outras maneiras de configurar o arquivo setup.py com abordagens diferentes. No entanto, eu sugeriria que esta é a melhor e mais fácil maneira de criar seu arquivo setup.py.

    2. README.rst file

    De acordo com fileinfo.com, a extensão .rst ou linguagem de marcação reStructuredText é um arquivo de texto que contém e suporta código escrito e estilizado. No site Sphinx, é detalhado que a extensão .rst é a principal linguagem de marcação para a criação e design de documentação de código. No entanto, este não é um arquivo realmente necessário para criar seu pacote privado, mas é essencial se um dia você quiser torná-lo público no pypi.org.

    clique em view raw para ver o formato de marcação.

    Your Django Package
    To install:
    
    pip install git+https://github.com/your_name/your_cart_package.git
    In your_project.settings.py add:
    
    INSTALLED_APPS = [
        ...
        'cart',
        ...
    ]
    Migrate the changes from the underwriting_manual app:
    
    $ python manage.py makemigrations cart
    
    $ python manage.py migrate cart
    In your_project.urls.py add:
    
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/', include('core.urls')),
        path('cart/', include('cart.urls')), # <=====
    ]
    RST

    3. Arquivo LICENSE.

    De acordo com a esri, um arquivo de licença é um arquivo de texto simples que fornece automaticamente as informações necessárias — como nome do produto, número de autorização e informações de contato do usuário — Software Authorization Wizard.

    Dependendo do nível de informação que você tem em seu aplicativo, eu aconselho você a ter um arquivo LICENSE bem adaptado para evitar qualquer problema no futuro. No entanto, o arquivo LICENSE também é essencial ao carregar seu pacote para pypi.org.

    /* Copyright (C) Your Company Systems, Inc - All Rights Reserved
     * Unauthorized copying of this file, via any medium is strictly prohibited
     * Proprietary and confidential
     * Written by your company attorney <you@yourcompany.com>, December 2021
     */
    Markdown

    Neste exemplo, usarei um modelo personalizado que pode ser editado por você:

    PS: Não sou advogado, portanto, o exemplo de licença não pode ser usado como um conselho ou exemplo do mundo real.

    4. MANIFEST.in file

    MANIFEST.in é um arquivo de texto que contém uma série de “comandos” em um formato definido pelo Distutils. Os comandos manifest permitem que você inclua ou exclua arquivos e diretórios específicos. Principalmente aqueles que não são reconhecidos pelo python como um diretório porque não contêm o init.py, como o diretório templates/ no Django. E arquivos que não têm a extensão .py e os arquivos que são usados ​​para construir o pacote, como LICENSE e README.rst.

    No entanto, o MANIFEST.in é basicamente um conjunto de comandos para incluir no pacote que será reconhecido pelo sdist ao construir seu pacote. Portanto, quando o pacote for criado, se um diretório ou arquivo for especificado, eles estarão lá quando o pacote for construído 😉.

    include LICENSE
    include README.rst
    recursive-include cart/templates *
    recursive-include cart/tests *
    INI

    Buildando o Pacote Django

    No momento em que você está seguindo este tutorial, no qual iniciamos apenas com o aplicativo cart , ele mudou. Portanto, se você fez tudo corretamente, seu diretório de trabalho deve ficar assim:

    seu_pacote_django/
      │   LICENSE
      │   MANIFEST.in
      │   README.rst
      │   setup.py
      │
      └───cart/
          │   admin.py
          │   apps.py
          │   contexts.py
          │   models.py
          │   urls.py
          │   views.py
          │   __init__.py
          │
          ├───migrations/
          │       __init__.py
          │
          ├───templates/
          │       cart.html
          │       header2.html
          │
          └───tests/
                  test_urls.py
                  test_views.py
                  __init__.py
    Bash

    Agora, há alguns passos que precisam ser seguidos para iniciar o processo de construção do seu pacote:

    Instale os pacotes sdist (distribuição de origem) e whell:

    pip install sdist && pip install wheel
    Bash

    nota: Eu consideraria criar um ambiente virtual e instalar os pacotes sdist e whell nele (não se esqueça de adicionar um arquivo .gitignore).

    Build do pacote Em Ação:

    No diretório raiz do pacote, adicione os seguintes comandos para finalmente compilar o pacote:

    python setup.py sdist && python setup.py bdist_wheel
    Bash

    Dessa forma o pacote será finalmente construído deixando você com o seguinte diretório:

    seu_pacote_django/
    │   .gitignore
    │   LICENSE
    │   MANIFEST.in
    │   README.rst
    │   setup.py
    │
    ├───build/
    │   ├───bdist.win-amd64
    │   └───lib
    │       └───cart/
    │           │   admin.py
    │           │   apps.py
    │           │   contexts.py
    │           │   models.py
    │           │   urls.py
    │           │   views.py
    │           │   __init__.py
    │           │
    │           ├───migrations/
    │           │       __init__.py
    │           │
    │           ├───templates/
    │           │       cart.html
    │           │       header2.html
    │           │
    │           └───tests/
    │                   test_urls.py
    │                   test_views.py
    │                   __init__.py
    │
    ├───cart/
    │   │   admin.py
    │   │   apps.py
    │   │   contexts.py
    │   │   models.py
    │   │   urls.py
    │   │   views.py
    │   │   __init__.py
    │   │
    │   ├───migrations/
    │   │       __init__.py
    │   │
    │   ├───templates/
    │   │       cart.html
    │   │       header2.html
    │   │
    │   └───tests/
    │           test_urls.py
    │           test_views.py
    │           __init__.py
    │
    ├───cart.egg-info/
    │       dependency_links.txt
    │       PKG-INFO
    │       SOURCES.txt
    │       top_level.txt
    │
    └───dist/
            cart-0.0.1-py3-none-any.whl
            cart-0.0.1.tar.gz
    Bash

    Instalando Seu Proprio Pacote Django

    O próximo passo para usar seu pacote é enviá-lo para um repositório do github para ser usado por você ou sua empresa.

    Então, você pode instalar o pacote pelo seguinte comando:

    Para repositório privado:

    pip install git+ssh://git@github.com:sua_conta/seu_pacote_django.git
    Bash

    Para repositório público:

    pip install git+https://github.com/sua_conta/seu_pacote_django.git
    Bash

    Faça uma pip list para verificar se o pacote do carrinho está instalado no seu ambiente virtual.

    $ pip list
    Package    Version
    ---------- -------
    pip        21.2.4
    cart        0.0.1   <-- Aqui
    Bash

    Portanto, seguindo este tutorial você aprendeu como construir seu próprio pacote Django que pode ser reutilizado entre diferentes projetos. Por último, mas não menos importante, embora este tutorial tenha exemplificado um aplicativo Django que foi transformado em um pacote, esta abordagem que você aprendeu tem o mesmo processo para criar qualquer pacote Python.

  • Testes Unitários Com Django

    Testes Unitários Com Django

    Testes unitários são basicamente umas das formas de saber se o código da aplicação que está sendo construída está no caminho correto, baseado nos requerimentos.

    Normalmente, e de forma correta, se constrói os testes para depois criar o código da aplicação, usando o teste em si como referência de funcionalidade.

    Como os testes funcionam

    Demorou para entrar na minha cabeça como os testes unitários funcionam. Eu sempre me perguntava: — Como assim, primeiro você cria os testes para depois criar o código? Isso não entra na minha cabeça!

    Isso é bem verdade, porém vamos usar uma analogia usando como exemplo uma fábrica metalúrgica com uma linha de montagem:

    Por exemplo uma empresa recebe o requisito para criar uma peça com todas as dimensões como requisitos, altura, largura e também o diâmetro da parede da mesma.

    Essas requisições são super importantes para que a peça se encaixe corretamente em um motor ou outra engrenagem, sendo assim, ficando perfeitamente adequada para os requisitos do cliente.

    Testes unitários

    Sendo torneiro mecânico em 2008 precisei usar testes para praticamente todas as peças que eu produzia para que as mesmas ficassem dentro do padrão do desenho/gabarito enviado pelo cliente.

    Era usado um molde com as especificações corretas onde se encaixavam as peças que eram feitas. Assim, junto com as medidas especificadas se sabia se o produto feito estava correto.

    Dessa forma ficou mais fácil entender o porquê de criar os testes primeiro para depois o código. Os testes são como o gabarito, o código são as peças criadas que serão testadas baseadas nos testes criados anteriormente (gabarito). Agora, creio que ficou mais fácil entender.

    Testando uma aplicação REST API Django

    Agora, vamos supor que recebemos um requisito para dois endpoints de uma aplicação de turismo:

    • Comments
    • Destinations

    Os requisitos são como a seguir:

    Como podemos ver, o modelo Comment tem um relacionamento de um para muitos com a tabela Destinations assim como os seus respectivos campos. Sendo assim, iniciaremos os testes para os modelos representados acima:

    tourism/tests/test_models.py

    # tourism/tests/test_models.py
    
    from django.test import TestCase
    from .models import Destinations, Comment
    from django.utils import timezone
    
    class TestModels(TestCase):
    
        def test_destinations_model(self):
            #test if Destinations model is passing correctly its values
            destination = Destinations.objects.create(
                tour_title = 'test1',
                booking_start_date='2021-05-30',
                booking_end_date= '2022-05-30',
                price=2000,
                description='test1',
                author='test1',
            )
            destination.save()
            self.assertEquals(destination.tour_title, 'test1')
            self.assertEquals(destination.booking_start_date, '2021-05-30')
            self.assertEquals(destination.booking_end_date, '2022-05-30')
            self.assertEquals(destination.price, 2000)
            self.assertEquals(destination.description, 'test1')
            self.assertEquals(destination.author, 'test1')
    
        def test_comment_model(self):
            #test if Comment model is related to Destinations model
            destination = Destinations.objects.create(
                tour_title = 'test1',
                booking_start_date ='2021-05-30',
                booking_end_date= '2022-05-30',
                price = 2000,
                description = 'test1',
                author = 'test1',
            )
            destination.save()
            comment = Comment.objects.create(
                #the relation between both models
                post = destination,
                name = 'John',
                email = 'any@email.com',
                comment = 'test1',
                created_on = timezone.now(),
                active = False,
            )
            comment.save()
            self.assertEquals(comment.post, destination)
    Python

    Como visto acima, foi herdada a classe TestCase do Django para poder testar os dois modelos Comment e Destinations na classe TestModels.

    Na função test_destinations_model(self) foi alocado o modelo Destinations em seu escopo, com uma query de criação feita no banco de dados de testes, usando o ORM do Django e com seus respectivos campos.

    https://wordpress.vps9144.panel.icontainer.cloud/introducao-ao-framework-django-compreendendo-o-framework-e-sua-arquitetura/

    Logo abaixo, é usado a função asserEquals(param1, param2) para saber se a mesma está sendo criada corretamente. Neste caso a função assertEquals() serve como o gabarito exemplificado na analogia e exemplo mencionado acima, para testar se o mesmo está sendo criado como deveria no banco de dados de testes.

    Vamos testar para ver se o teste retorna como correto, “OK”:

    python manage.py test
    Found 1 test(s).
    System check identified no issues (0 silenced).
    E
    ====================================================================
    ERROR: tourism.tests (unittest.loader._FailedTest)
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    ImportError: Failed to import test module: tourism.tests
    Traceback (most recent call last):
    …
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    Ran 1 test in 0.000s
    Bash

    Como visto, ao tentar rodar os testes o mesmo não funcionou pois não tem oque testar ainda, as classes/tabelas ainda não foram criadas.

    Agora vamos criar as tabelas como no requerimento e seus consecutivos relacionamentos e rodar os testes novamente:

    tourism/models.py:

    # tourism/models.py
    
    from django.db import models
    
    # Create your models here.
    class Destinations(models.Model):
        author = models.CharField(max_length=200, unique=False)
        tour_title = models.CharField(max_length=250)
        description = models.TextField()
        location = models.CharField(max_length=250)
        booking_start_date = models.DateField()
        booking_end_date = models.DateField()
        price = models.DecimalField(max_digits=6, decimal_places=2)
    
        def __str__(self):
            return str(self.tour_title)
    
    
    class Comment(models.Model):
        post = models.ForeignKey(Destinations,
           on_delete=models.CASCADE,related_name='comments')
        name = models.CharField(max_length=80)
        email = models.EmailField()
        comment = models.TextField()
        created_on = models.DateTimeField(auto_now_add=True)
        active = models.BooleanField(default=False)
    
        def __str__(self):
            return str(self.name)
    Python

    Depois de criar os modelos e fazer as migrations vamos testar para ver se os valores batem com os testes:

    python manage.py test
    Found 2 test(s).
    Creating test database for alias 'default'...
    System check identified no issues (0 silenced).
    ..
    --------------------------------------------------------------------
    Ran 2 tests in 0.005s
    
    OK
    Destroying test database for alias 'default'...
    Bash

    Criando testes para os endpoints da aplicação REST API

    Agora para testar os endpoints desta aplicação sera necessário criar a representação dos dados da mesma forma que foi efetuado para testar os modelos.

    E também a representação dos dados e URLs para testar o CRUD em cada endpoint (Destinations e Comments).

    Criando esse setup dentro da classe de testes, sera necessário criar funções que testam cada operação CRUD dos endpoints.

    https://wordpress.vps9144.panel.icontainer.cloud/django-rest-framework-construindo-apis-restful-com-django/

    No código abaixo foi criado quatro funções para cada endpoint usando os dados adicionados ao método Setup(), sendo assim, testando cada método de requisição Create, Read, Update e Delete:

    tourism/tests/test_api.py:

    # tourism/tests/test_api.py
    
    import json
    from rest_framework import status
    from django.utils import timezone
    from django.http import response
    from django.urls import reverse
    from tourism.models import Destinations, Comment
    from rest_framework.authtoken.models import Token
    from rest_framework.test import APIClient, APITestCase
    
    
    class TourismTestCase(APITestCase):
    
        def setUp(self):
            
            self.headerInfo = {'content-type': 'application/json'}
            
            # PASSO 1
    
            # Criação de objetos que serão 
            # utilizados nos testes dos endpoints.
    
            # Instance do objeto Destinations.
            self.destination = Destinations.objects.create(
                tour_title = 'test1',
                booking_start_date='2021-05-30',
                booking_end_date= '2022-05-30',
                price=2000,
                description='test1',
                location='somewhere',
                author='test1',
            )
            self.destination.save()
    
            # Instance do objeto Comment.
            self.comment = Comment.objects.create(
                #the relation between both models
                post = self.destination,
                name = 'John',
                email = 'any@email.com',
                comment = 'test1',
                created_on = timezone.now(),
                active = False,
            )
            self.comment.save()
    
            # PASSO 2
    
            # Criação de dados para serem usados nos testes.
            self.destination_data = {
                'tour_title' :'test1',
                'booking_start_date':'2021-05-30',
                'booking_end_date':'2022-05-30',
                'price':2000,
                'description':'test1',
                'location':'somewhere',
                'author':'test1'
            }
    
            self.comment_data = {
                'post':self.destination.id,
                'name':'John',
                'email':'any@email.com',
                'comment':'test1',
                'created_on':timezone.now(),
                'active':False,
            }
    
            # PASSO 3
    
            # Criação da representação dos endpoints
            # que serão utilizados nos testes.
    
            self.url_destination_list = reverse('tourism:destinations-list')
            self.url_destination_detail = reverse('tourism:destinations-detail',
                                            kwargs={'pk': self.destination.pk})
    
            self.url_comment_url_list = reverse('tourism:comments-list')
            self.url_comment_detail = reverse('tourism:comments-detail', 
                                            kwargs={'pk': self.comment.pk})
    
        # PASSO 4
        
        # Usar os dados criados no setUp() 
        # para criar as funções de teste.
    
        def test_get_destination(self):
            """GET method"""
            response = self.client.get(self.url_destination_list, format='json')
            self.assertEqual(response.status_code, status.HTTP_200_OK)
    
        def test_create_destination(self):
            """ Test POST method for Destination endpoint"""
            response = self.client.post(
                self.url_destination_list, self.destination_data,
                format='json'
            )
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
    
        def test_update_destination(self):
            """ Test PUT method for Destination endpoint"""
            response = self.client.put(
                self.url_destination_detail, self.destination_data,
                format='json'
            )
            self.assertEqual(response.status_code, status.HTTP_200_OK)
    
        def test_delete_destination(self):
            """ Test DELETE method for Destination endpoint"""
            response = self.client.delete(
                self.url_destination_detail, format='json'
            )
            self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
    
        def test_get_comment(self):
            """GET method"""
            response = self.client.get(self.url_comment_url_list, format='json')
            self.assertEqual(response.status_code, status.HTTP_200_OK)
    
        def test_create_comment(self):
            """ Test POST method for Comment endpoint"""
            response = self.client.post(
                self.url_comment_url_list, self.comment_data,
                format='json'
            )
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
    
        def test_update_comment(self):
            """ Test PUT method for Comment endpoint"""
            response = self.client.put(
                self.url_comment_detail, self.comment_data,
                format='json'
            )
            self.assertEqual(response.status_code, status.HTTP_200_OK)
    
        def test_delete_comment(self):
            """ Test DELETE method for Comment endpoint"""
            response = self.client.delete(
                self.url_comment_detail, format='json'
            )
            self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
    Python

    Seguindo os exemplos acima sabemos que ao rodar o teste o mesmo não passará, pois ainda não foi criado os endpoints de Destinations e Comments.

    Desta maneira foi criado as URLs do app e adicionado na URL principal:

    project_name/urls.py:

    # project_name/urls.py
    
    from django.urls import include, path
    from rest_framework import routers
    from tourism.api.viewsets import DestinationsViewset, CommentViewset
    
    router = routers.DefaultRouter()
    router.register(r"destinations", DestinationsViewset, basename="destinations")
    router.register(r"comments", CommentViewset, basename="comments")
    
    app_name = 'tourism'
    
    urlpatterns = [
        path('', include(router.urls)),
    ]    
    Python

    project_name/url.py

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/', include('tourism.urls')), # <------------ a inserção de tourism.urls.
    ]
    Python

    Também sera criados os serializers e também os viewsets para que os dados sejam serializados pelo framework django-rest-framework e aceitem postagens e edições de dados em formato JSON.

    tourism/api/serializers.py

    from django.forms import modelformset_factory
    from rest_framework import serializers
    from tourism.models import Destinations, Comment
    
    class DestinationsSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = Destinations
            fields = '__all__'
    
    
    class CommentSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = Comment
            fields = '__all__'
    Python

    tourism/api/viewsets.py:

    from rest_framework import viewsets
    from .serializers import DestinationsSerializer, CommentSerializer
    from tourism.models import Destinations, Comment
    
    
    class DestinationsViewset(viewsets.ModelViewSet):
        queryset = Destinations.objects.all()
        serializer_class = DestinationsSerializer
    
    class CommentViewset(viewsets.ModelViewSet):
        queryset = Comment.objects.all()
        serializer_class = CommentSerializer
    Python

    Agora que os dados necessários foram adicionados para a serialização dos mesmos, os testes serão aceitos corretamente fazendo entender que os endpoints estão funcionando corretamente:

    python manage.py test
    Found 10 test(s).
    Creating test database for alias 'default'...
    System check identified no issues (0 silenced).
    ..........
    --------------------------------------------------------------------
    Ran 10 tests in 0.061s
    
    OK
    Destroying test database for alias 'default'...
    Bash

    Voce pode ter acesso ao codigo deste artigo aqui

  • Views e URLs no Django: Fundamentos Para Gerenciar Rotas

    Views e URLs no Django: Fundamentos Para Gerenciar Rotas

    Django é um framework popular que ajuda desenvolvedores a criar aplicações web rapidamente e de maneira eficiente. Ele segue a arquitetura Model-View-Template (MVT), onde as views têm um papel essencial na entrega de conteúdo dinâmico aos usuários.

    Além das views, o roteamento de URLs no Django é o mecanismo que mapeia solicitações de URLs para as views corretas, garantindo que o usuário acesse o conteúdo desejado com facilidade.

    Neste post, vamos explorar em profundidade como views e roteamento de URLs no Django funcionam, destacando seus aspectos fundamentais e apresentando exemplos práticos para ajudar no desenvolvimento de páginas web dinâmicas e eficientes.

    O que são Views no Django

    No Django, as views são responsáveis por processar as solicitações HTTP que um servidor recebe e por retornar uma resposta apropriada. Essa resposta pode ser uma página HTML, um documento JSON, um arquivo ou qualquer outro tipo de dado que o cliente esteja esperando.

    Django mvt

    As views interagem com os modelos e templates, e basicamente controlam a lógica do que acontece quando um usuário acessa uma determinada URL.

    Existem dois tipos principais de views no Django:

    1. Views baseadas em função (Function-based views – FBVs).
    2. Views baseadas em classe (Class-based views – CBVs).

    Vamos explorar esses dois tipos em detalhe.

    Views baseadas em Função

    As views baseadas em função são simples funções Python que recebem um objeto request e retornam um objeto response. Elas são uma ótima escolha para projetos menores ou para views que não precisam de uma estrutura mais complexa.

    Um exemplo básico de view baseada em função:

    from django.http import HttpResponse
    
    def index(request):
        return HttpResponse("Bem-vindo à página inicial!")
    Python

    Aqui, temos uma função chamada index que recebe o objeto request e retorna uma resposta HTTP com o texto “Bem-vindo à página inicial!“. Essa view é simples e direta, o que torna o seu uso adequado para tarefas rápidas.

    https://wordpress.vps9144.panel.icontainer.cloud/introducao-ao-framework-django-compreendendo-o-framework-e-sua-arquitetura/#comments

    Views baseadas em Classe

    As views baseadas em classe oferecem uma abordagem mais estruturada e reutilizável para desenvolver views.

    Elas são especialmente úteis quando você precisa de mais flexibilidade ou quando a lógica da sua view é mais complexa.

    As views baseadas em classe no Django herdam de classes genéricas, o que facilita muito a implementação de funcionalidades comuns como exibição de listas, formulários e operações CRUD (Create, Read, Update, Delete).

    Exemplo de uma view baseada em classe:

    from django.views import View
    from django.http import HttpResponse
    
    class IndexView(View):
        def get(self, request):
            return HttpResponse("Bem-vindo à página inicial!")
    Python

    Nesse caso, a classe IndexView herda da classe base View, e implementamos o método get para processar as solicitações do tipo GET.

    O que é o Roteamento de URLs no Django

    O roteamento de URLs no Django é o mecanismo que conecta as URLs às suas respectivas views. O Django utiliza um sistema de mapeamento simples e eficiente, que permite direcionar URLs para as views corretas sem a necessidade de configurá-las manualmente para cada endpoint.

    Para definir as rotas no Django, utilizamos o arquivo urls.py, onde as URLs são associadas a views específicas. O roteamento de URLs no Django é simples, mas extremamente poderoso, permitindo também o uso de parâmetros dinâmicos nas URLs.

    Configurando URLs no Django

    Cada aplicativo no Django geralmente contém um arquivo urls.py, que define suas rotas. Além disso, o projeto principal também tem um arquivo urls.py para gerenciar as rotas globais. Aqui está um exemplo básico de como configurar o roteamento de URLs no Django:

    from django.urls import path
    from .views import index
    
    urlpatterns = [
        path('', index, name='index'),  # <-- Mapeia a URL raiz para a view index
    ]
    Python

    Neste exemplo, a URL raiz ('/') está associada à view index. Quando um usuário acessa o domínio principal, a função index será chamada e processará a solicitação.

    URLs com Parâmetros

    O roteamento de URLs no Django também permite a criação de rotas dinâmicas, onde parâmetros são passados pela URL para serem usados na view correspondente. Esse recurso é muito útil para construir URLs como '/perfil/usuario123/‘, onde o usuario123 é um parâmetro dinâmico.

    Exemplo de URL com parâmetro:

    from django.urls import path
    from .views import saudacao
    
    def saudacao(request, nome):
        return HttpResponse(f"Olá, {nome}!")
    
    urlpatterns = [
        path('saudacao//', saudacao, name='saudacao'),  # <-- Passa 'nome' como parâmetro
    ]
    
    Python

    Nesse caso, o Django captura o valor na URL e passa como argumento para a função saudacao. Quando a URL /saudacao/Joao/ é acessada, o Django chamará a função view e passará o valor Joao para a variável nome.

    Trabalhando com Templates e Views

    As views no Django também são responsáveis por renderizar templates, que são arquivos HTML que exibem informações dinâmicas aos usuários. A renderização de templates separa a lógica da aplicação da apresentação, garantindo um código mais organizado e de fácil manutenção.

    Exemplo de View com Template

    Abaixo, um exemplo de uma view que renderiza um template HTML usando o atalho render():

    from django.shortcuts import render
    
    def index(request):
        contexto = {'mensagem': 'Bem-vindo ao Django! :D'}
        return render(request, 'index.html', contexto)
    Python

    Neste exemplo, a função index renderiza o template index.html e passa um dicionário chamado contexto para o template. No template, você pode usar a variável mensagem para exibir o texto dinamicamente.

    Django

    Criando Templates Simples

    Os templates do Django são arquivos HTML que contêm tags específicas para lidar com variáveis e controle de fluxo, como laços e condicionais. Aqui está um exemplo básico de template:

    DOCTYPE html>
    <html lang="pt-br">
    <head>
        <meta charset="UTF-8">
        <title>Página Inicialtitle>
    head>
    <body>
        <h1>{{ mensagem }}h1>
    body>
    html>
    HTML

    Quando a view index renderiza este template, a variável mensagem será substituída pelo valor passado no contexto, resultando em algo assim na página web:

    Bem-vindo ao Django! 😀

    Views Genéricas no Django

    Além das views baseadas em função e classe, o Django oferece uma série de views genéricas que automatizam muitas das tarefas comuns ao desenvolver aplicações web. Essas views genéricas cobrem casos de uso como exibição de listas de objetos, detalhes de um objeto, criação, edição e exclusão.

    ListView e DetailView

    Duas das views genéricas mais utilizadas são ListView e DetailView. Elas ajudam a listar e exibir os detalhes de objetos sem precisar escrever toda a lógica de exibição do zero.

    Aqui está um exemplo de uma ListView para listar posts de um blog:

    from django.views.generic import ListView
    from .models import Post
    
    class PostListView(ListView):
        model = Post
        template_name = 'post_list.html'
        context_object_name = 'posts'
    Python

    Neste exemplo, PostListView automaticamente buscará todos os objetos do modelo Post e os enviará ao template post_list.html sob o nome de contexto posts.

    FormView

    O Django também fornece views genéricas para lidar com formulários. A FormView, por exemplo, facilita o processo de exibição e validação de formulários sem que você precise codificar manualmente todo o processo.

    Exemplo de FormView:

    from django.views.generic.edit import FormView
    from .forms import ContatoForm
    
    class ContatoFormView(FormView):
        template_name = 'contato.html'
        form_class = ContatoForm
        success_url = '/obrigado/'
    
        def form_valid(self, form):
            # Processa o formulário
            return super().form_valid(form)
    Python

    Aqui, a ContatoFormView exibe o formulário definido em ContatoForm, valida os dados submetidos e, se tudo estiver correto, redireciona para uma página de sucesso.

    Melhores Práticas no Uso de Views e Roteamento de URLs no Django

    Ao desenvolver com Django, é importante seguir algumas melhores práticas para garantir que suas views e URLs sejam eficientes, escaláveis e fáceis de manter. Algumas dicas incluem:

    1. Organização de URLs: Divida suas URLs em vários arquivos urls.py dentro dos aplicativos para evitar que o arquivo principal se torne muito grande e confuso.
    2. Uso de Namespaces: Utilize namespaces para agrupar as rotas de diferentes aplicativos. Isso ajuda a evitar conflitos de nomes de URLs.
    3. Classes View para Código Reutilizável: Sempre que possível, prefira views baseadas em classe para código mais organizado e reutilizável.
    4. Atenção ao Desempenho: Em views que fazem muitas consultas ao banco de dados, utilize o método select_related() ou prefetch_related() para otimizar as queries e reduzir o número de acessos ao banco.

    Conclusão

    Entender views e roteamento de URLs no Django é fundamental para o desenvolvimento de páginas dinâmicas e eficientes.

    Enquanto as views controlam a lógica de como as informações são processadas e exibidas. O roteamento de URLs garante que as solicitações do usuário sejam corretamente direcionadas para as views corretas.

    Ao dominar essas duas áreas, você estará preparado para desenvolver aplicações web robustas e escaláveis com Django, utilizando os melhores recursos que o framework tem a oferecer.

  • Interface De Administração Do Django

    Interface De Administração Do Django

    O Django é um dos frameworks mais populares e completos para desenvolvimento web em Python. Criado para facilitar a construção de aplicações web complexas com menos código e maior eficiência, ele segue o padrão “Model-View-Template” (MVT), o que facilita a separação lógica entre os dados, a interface de usuário e o processamento de regras de negócio.

    Uma das funcionalidades mais marcantes do Django é sua interface de administração que ja vem por padrão, conhecida como Django Admin.

    Desde a criação de um novo projeto, o Django fornece uma interface de administração completamente funcional e altamente personalizável. O que permite gerenciar com facilidade o conteúdo da aplicação sem precisar desenvolver um painel de controle do zero.

    O Django Admin tem sido um dos recursos favoritos de desenvolvedores e equipes de conteúdo, pois oferece uma maneira rápida de gerenciar modelos, usuários e permissões.

    Ele é projetado para ser usado tanto por desenvolvedores quanto por administradores de conteúdo, eliminando a necessidade de interfaces administrativas complexas ou construídas do zero.

    Neste post, você irá entender como configurar e usar o Django Admin para gerenciar o conteúdo da sua aplicação de maneira eficiente e profissional.

    Configuração Inicial do Projeto

    Antes de começar a utilizar o Django Admin, é necessário realizar algumas configurações básicas. Como a instalação do projeto e o app, para em seguida iniciarmos os proximos passos.

    Criando Um Ambiente Virtual

    Antes de tudo vamos iniciar a criação de um projeto django, é necessario a criação de um ambiente virtual python para isolarmos nossa aplicação.

    python3 -m venv venv
    Bash

    Criação De Um Projeto Django

    Adicione os comandos a seguir em sequência:

    # 1. cria o projeto
    django-admin startproject meu_projeto . 
    
    # 2. cria o app
    django-admin startapp postagens 
    Bash

    Conexão Do App De Postagens Com o Projeto

    Agora que o projeto e o aplicativo de postagens foram criados, podemos fazer a conexão do aplicativo no projeto:

    Em settings.py adicone o nome do aplicativo no seguinte lugar:

    INSTALLED_APPS = [
        # Outros aplicativos
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'postagens', # <---------------------- Aqui
    ]
    Python

    Criando Um Super Usuario

    Depois de conectar o aplicationvo no projeto, usando o settings.py, é hora de acessar a interface de administração, criando um super-usuário. No qual é um usuário com permissões completas sobre o sistema:

    python manage.py createsuperuser
    Bash

    Siga as instruções fornecidas no terminal para definir o nome de usuário, e-mail e senha. Uma vez concluído, o seu superusuário estará criado e pronto para acessar o site de administrador do django.

    Acessando a Interface De Administração (django admin)

    Após isso, já podemos iniciar o servidor de desenvolvimento para garantir que tudo está funcionando corretamente:

    python manage.py runserver
    Bash

    Com o servidor rodando, acesse a interface de administração navegando até a URL padrão:

    http://127.0.0.1:8000/admin/
    Bash

    Você verá uma tela de login, onde poderá inserir as credenciais do superusuário que acabou de criar.

    Admin Login Site

    Ao entrar, você será levado à página inicial da interface administrativa do Django, onde você poderá visualizar modelos registrados, gerênciar usuários e realizar outras tarefas administrativas.

    Registrando Modelos No Django Admin

    Porém como visto na imagem acima, podemos perceber que temos apenas os modelos padrões do proprio Django.

    Com isso, Agora que você já tem a interface do Django Admin funcionando, é hora de adicionar seus modelos para que eles possam ser gerenciados através dessa interface.

    O Que São Modelos No Django?

    No Django, os modelos representam as tabelas do banco de dados. Cada classe de modelo que você define em seu código Python é mapeada para uma tabela no banco de dados. Esses modelos contêm campos que representam colunas na tabela, como nome, e-mail, data de criação, entre outros.

    Registrando Modelos No Django Admin

    Por padrão, o Django Admin não exibe todos os modelos automaticamente. Você precisa registrar os modelos que deseja gerenciar na interface administrativa. Para isso, vá até o arquivo admin.py no seu aplicativo (caso não exista, crie o arquivo). Suponha que você tenha um modelo de Post de blog, como este:

    # postagens/models.py
    
    from django.db import models
    
    class Post(models.Model):
        titulo = models.CharField(max_length=200)
        conteudo = models.TextField()
        publicado_em = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.titulo
    Python

    Para registrar este modelo no Django Admin, edite o arquivo admin.py e adicione o seguinte código:

    # postagens/admin.py
    
    from django.contrib import admin
    from .models import Post # <--------- Não se esqueça do import
    
    admin.site.register(Post) # <----- Registro do model no site admin
    Python

    Após isso, ao voltar à interface administrativa e atualizar a página, você verá o modelo Post disponível para gerenciamento.

    Django Admin With Posts Image

    Customização Básica Do Django Admin

    É possível personalizar como os dados aparecem na interface administrativa. No Django Admin, você pode modificar como os campos do modelo são exibidos na lista de objetos ou no formulário de edição.

    Adicionando alguns dados (Posts) vamos dar uma olhada de como as postagens aparecem por padrão:

    1 – Criação de postagem

    2 – Depois da criação das postagens, desta form que ficará a listagem dos mesmos (padrão):

    Lembrando que os dados estão listados assim por causa do metodo __str__ que adicionamos la no model 😉

    Agora vamos adicionar uma nova classe chamada PostAdmin para modificar a maneira que listamos as postagens no site admin do django:

    # postagens/admin.py
    
    from django.contrib import admin
    from .model import Post
    
    class PostAdmin(admin.ModelAdmin):
        list_display = ('titulo', 'publicado_em')
        search_fields = ('titulo',)
    
    admin.site.register(Post, PostAdmin)
    Python

    Aqui, list_display define os campos que serão exibidos na lista de itens, e search_fields permite a criação de uma barra de pesquisa para filtrar os resultados pelo campo título.

    Assim que você adicionar e salvar essas mudanças, recarregue a pagina para ver as mudanças no admin site:

    Customizando a Interface De Edição De Postagens no Django Admin

    A verdadeira força do Django Admin está na sua extensibilidade. Com a classe ModelAdmin, você pode customizar praticamente tudo na interface administrativa para se adequar às suas necessidades.

    Organizando Campos No Formulário

    A interface de edição padrão do Django Admin exibe todos os campos de um modelo em um layout vertical simples. No entanto, você pode organizá-los de maneira mais estruturada. Usando o atributo fieldsets, é possível agrupar campos e adicionar títulos:

    # postagens/admin.py
    
    from django.contrib import admin
    from .models import Post
    
    # Register your models here.
    class PostAdmin(admin.ModelAdmin):
        fieldsets = ( # <------------------- Novo campo
            ('Informações Básicas', {
                'fields': ('titulo',)
            }),
            ('Conteúdo', {
                'fields': ('conteudo',)
            }),
        )
        list_display = ('titulo', 'publicado_em')
        search_fields = ('titulo',)
    
    admin.site.register(Post, PostAdmin)
    Python

    Antes de adicionar esses valores no seu codigo, entre nos detalhes de uma postagem e veja como os campos estao por padrão:

    Agora, adcione o codigo acima com o novo campo e observe as mudanças:

    Como voce pode ver, cada campo teve a adição de um cabeçalho explicando seu proposito.

    Criando Ações Customizadas

    Além de gerenciar os dados exibidos, você também pode definir ações customizadas que podem ser aplicadas em lote. Por exemplo, para criar uma ação que marca vários posts como despublicados:

    Adicionando Um Novo Campo No Model Post

    Nesse caso, na model de postagens eu irei adicionar um novo campo chamado publicado que pode ser verdadeiro ou falso (BoooleanField(default=True)):

    # postagens/models.py
    
    from django.db import models
    
    class Post(models.Model):
        titulo = models.CharField(max_length=200)
        conteudo = models.TextField()
        publicado_em = models.DateTimeField(auto_now_add=True)
        publicado = models.BooleanField(default=True) # <-------- Noco campo
    
        def __str__(self):
            return self.titulo
    Python

    Criando As Migrations e Refletindo No Banco De Dados

    Assim que este codigo for adicionado, será necessario fazer os comandos para criar um novo arquivo de migration dentro da aplicação e outro comando para refletir este novo arquivo no banco de dados:

    # Comando para criar arquivo de migrations
    python manage.py makemigrations
    
    # Comando para refletir a migration no banco de dados.
    python manage.py migrate
    Bash

    Assim que esses comandos forem efetuados, voce estara pronto/apto para efetuar tambem as mudanças no site admin (no mesmo arquivo e a mesma classe que estavamos trabalhando antes).

    Adicionando Um Novo Campo e Criando Nova Ação Customizada

    # postagens/admin.py
    
    from django.contrib import admin
    from .models import Post
    
    def despublicar_post(modeladmin, request, queryset): <--- Nova função
        """
        Muda o status de uma 
        postagem para despublicado.
        """
        queryset.update(publicado=False)
    
    # Register your models here.
    class PostAdmin(admin.ModelAdmin):
        actions = [despublicar_post] <--- Ação adicionada com o nome da função criada acima.
        
        fieldsets = ( 
            ('Informações Básicas', {
                'fields': ('titulo',)
            }),
            ('Conteúdo', {
                'fields': ('conteudo',)
            }),
            ('Estatus', { <--- Novo campo adicionado para listagem
                'fields': ('publicado',)
            }),
        )
        list_display = ('titulo', 'publicado_em', 'publicado')
        search_fields = ('titulo',)
    
    despublicar_post.short_description = 'Marcar posts como despublicados'
    
    admin.site.register(Post, PostAdmin)
    Python

    Desta forma na listagem de postagens sera mostrado um novo campo detalhando se a postagem esta publicada ou não, e tambem o poder de despublicar varias postagens de uma vez.

    Checando as mudanças

    Neste caso eu irei apenas despublicar a primeira postagem para deixar o resultado como exemplo abaixo:

    Como pode ver, a postagem foi despublicada. Neste caso, ao clicar no “dropdown” e escolhido a ação de desplublicar, a função despublicar_post() foi acionada mudando o estatus desta postagem. Porem, caso necessite efetuar a mundaçã de estatus (deixar o mesmo como publicado).

    Simplesmente, clique na postagem no qual efetuamos o estatus de publicado anteriormente e clique para que o mesmo fique com o estatus de publicado novamente.

    Aproveite o código desta aplicação e continue com este projeto

    Conclusão

    O Django Admin é uma das funcionalidades mais convenientes e poderosas para quem desenvolve aplicações com o Django.

    Lembrando que essas mudanças no site admin são apenas algumas que e possivel efetuar. Existe uma gama enorme de possibilidades que podemos aplicar alem dessas.

    Sendo assim, ao entender como configurar e customizar a interface de administração, é possível gerenciar o conteúdo de maneira eficiente e segura.

    Se usado corretamente, ele elimina a necessidade de construir um painel administrativo do zero, poupando tempo e recursos.

  • Mapeamento objeto-relacional (ORM) Em Operações De Banco De Dados

    Mapeamento objeto-relacional (ORM) Em Operações De Banco De Dados

    Como desenvolvedor, simplificar as interações do banco de dados (como o uso de ORM), mantendo a eficiência, é crucial.

    Sem mencionar que, em alguns casos, devemos nos concentrar em entregar o produto rapidamente, sem muitas abstrações, e criar um ORM pode remover essa camada de complexidade para focar no produto em si.

    Portanto, hoje, vamos nos aprofundar na criação de um ORM, uma ferramenta poderosa que agiliza as operações do banco de dados, encapsulando-as em classes e métodos intuitivos.

    Criação da classe e inicialização do ORM:

    O método __init__ inicializa o ORM estabelecendo uma conexão com o banco de dados SQLite usando o módulo sqlite3.

    import sqlite3
    
    class SimpleORM:
    
      def __init__(self, db_name):
        self.conn = sqlite3.connect(db_name)
        self.cursor = self.conn.cursor()
    Python

    Além disso, adicionando uma nova variável que permite a criação de consultas neste banco de dados já conectamos.

    Iniciando uma nova conexão com o banco de dados via ORM:

    Nessa abordagem, estabelecemos uma conexão com o banco de dados usando a classe SimpleORM, permitindo a execução de várias consultas dentro do banco de dados especificado.

    Como é evidente, o ‘db.sqlite3‘ representa o caminho do arquivo onde o banco de dados está localizado, designado dentro do método sqlite3.connection() para estabelecimento da conexão.

    Criando tabelas com o método create_table na ORM:

    O método create_table habilita a criação de tabelas dentro do banco de dados. Ele recebe parâmetros para table_name e colunas, executando a consulta SQL para criar a tabela se ela ainda não existir.

    def create_table(self, table_name, columns):
      self.cursor.execute(f"CREATE TABLE IF NOT EXISTS {table_name} ({columns})")
      self.conn.commit()
    Python

    Portanto, usar essa abordagem pode facilitar a criação de uma tabela simples com a redução de pequenas melhorias, mas sem muita complicação.

    Criando uma nova tabela com o método create_table:

    # Create a table with an auto-incremental ID
    orm.create_table("users", "id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER")
    Python

    Neste cenário, há alterações mínimas necessárias para a criação da tabela. No entanto, algumas intricadas e complexidades de consultas SQL, como definições de nomes de colunas. Elas podem ser simplificadas pela introdução de um BaseModel. (Vou me aprofundar mais nessa abordagem em um próximo post).

    Inserindo dados na tabela criada usando o método insert_data:

    O método insert_data insere dados na tabela especificada. Ele gera dinamicamente a consulta SQL, inserindo dados passados ​​como argumentos na tabela designada.

    # Os outros metodos acima....
    
    def insert_data(self, table_name, **kwargs):
      columns = ", ".join(kwargs.keys())
      placeholders = ", ".join(["?"] * len(kwargs))
      query = f"INSERT INTO {table_name} ({columns}) VALUES ({placeholders})"
      values = tuple(kwargs.values())
      self.cursor.execute(query, values)
      self.conn.commit()
    Python

    A propósito, como funciona? O método insert_data() cria dinamicamente uma consulta SQL INSERT gerando nomes de colunas e espaços reservados para valores com base no nome da tabela e argumentos de palavra-chave fornecidos.

    Em seguida, ele executa essa consulta para inserir dados na tabela especificada usando o cursor, confirmando as alterações no banco de dados posteriormente.

    Esse método permite a inserção flexível de dados em tabelas sem especificar explicitamente nomes de colunas na consulta, aproveitando os argumentos de palavra-chave fornecidos como pares coluna-valor.

    Como usar o método insert_data():

    # Insert data (ID é auto-incrementado)
    orm.insert_data("users", name="John", age=32)
    orm.insert_data("users", name="Maria", age=22)
    Python

    Neste exemplo foram utilizadas duas consultas para adicionar duas linhas dentro da tabela users.

    Lendo dados de uma tabela específica com o método read_data():

    # Os outros metodos acima....
    
    def read_data(self, table_name):
      self.cursor.execute(f"SELECT * FROM {table_name}")
      return self.cursor.fetchall()
    Python

    O método read_data() é simples, até agora ele só lê todos os dados de uma tabela específica. Basicamente, é similar a TableName.objects.all() usando o Django ORM.

    Usando o método read_data():

    # Ler e print data
    data = orm.read_data("users")
    print("Data:", data)
    
    # Resultado ---
    # Data: [(1, 'John', 32), (2, 'Maria', 22)]
    Python

    Este é o resultado do metodo read_data().

    Atualizando linhas dentro de tabelas específicas usando o método update_data():

    # Os outros metodos acima....
    
    def update_data(self, table_name, id, **new_data):
      set_values = ", ".join([f"{key} = ?" for key in new_data.keys()])
      query = f"UPDATE {table_name} SET {set_values} WHERE id = ?"
      values = tuple(new_data.values()) + (id,)
      self.cursor.execute(query, values)
      self.conn.commit()
    Python

    O método update_data() é um pouco mais complexo, pois precisa atualizar uma linha específica dentro de uma tabela. Usando os argumentos kword para criar a consulta dinamicamente.

    Usando o metodo updated_data():

    # Update data
    orm.update_data("users", id=1, name="Alicy", age=27)
    updated_data = orm.read_data("users")
    print("Updated Data:", updated_data)
      
    # Resultado ---
    # Data: [(1, 'Alicy', 27), (2, 'Maria', 22)]
    Python

    Aqui está o método update_data() em ação. Seguindo a implementação acima, ele obtém as chaves dos novos valores dos argumentos (id, name, age) para inseri-los no lugar dos dados antigos na consulta. Além disso, os valores (1, ‘Alicy’ e 27) são inseridos como tupla na variável values, após a consulta ser executada no banco de dados.

    Excluindo dados de uma tabela específica usando o método delete_data():

    # Os outros metodos acima....
    
    def delete_data(self, table_name, id):
      query = f"DELETE FROM {table_name} WHERE id = ?"
      self.cursor.execute(query, (id,))
      self.conn.commit()
    Python

    O método delete_data() não é um método muito complexo deste exemplo de ORM. Basicamente, ele recebe dois parâmetros, como table_name e id, os insere na consulta DELETE, executa e confirma o código no banco de dados.

    Entenda mais sobre ORM nesta postagem.

    Usando o método delete_data():

    # Delete data
    orm.delete_data("users", id=3)
    new_data = orm.read_data("users")
    print("Dados depois de deletar id especifico:", new_data)
    
    # Resultado ---
    # Dados depois de deletar id especifico: [(2, 'Maria', 22)]
    Python

    Este é um exemplo do metodo delete_data().

    Como o codigo ficara finalizado:

    import sqlite3
    
    class SimpleORM:
        def __init__(self, db_name):
            self.conn = sqlite3.connect(db_name)
            self.cursor = self.conn.cursor()
    
        def create_table(self, table_name, columns):
            self.cursor.execute(f"CREATE TABLE IF NOT EXISTS {table_name} ({columns})")
            self.conn.commit()
    
        def insert_data(self, table_name, **kwargs):
            columns = ", ".join(kwargs.keys())
            placeholders = ", ".join(["?"] * len(kwargs))
            query = f"INSERT INTO {table_name} ({columns}) VALUES ({placeholders})"
            values = tuple(kwargs.values())
            self.cursor.execute(query, values)
            self.conn.commit()
    
        def read_data(self, table_name):
            self.cursor.execute(f"SELECT * FROM {table_name}")
            return self.cursor.fetchall()
    
        def update_data(self, table_name, id, **new_data):
            set_values = ", ".join([f"{key} = ?" for key in new_data.keys()])
            query = f"UPDATE {table_name} SET {set_values} WHERE id = ?"
            values = tuple(new_data.values()) + (id,)
            self.cursor.execute(query, values)
            self.conn.commit()
    
        def delete_data(self, table_name, id):
            query = f"DELETE FROM {table_name} WHERE id = ?"
            self.cursor.execute(query, (id,))
            self.conn.commit()
    
        def close_connection(self):
            self.conn.close()
    
    # Example usage:
    if __name__ == "__main__":
        orm = SimpleORM("db.sqlite3")
    
        # Create a table with an auto-incremental ID
        orm.create_table("users", "id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER")
    
        # Insert data (ID is auto-incremented)
        orm.insert_data("users", name="John", age=32)
    
        # Read and print data
        data = orm.read_data("users")
        print("Data:", data)
    
        # Update data
        orm.update_data("users", id=1, name="Alicy", age=27)
        updated_data = orm.read_data("users")
        print("Updated Data:", updated_data)
    
        # Delete data
        orm.delete_data("users", id=3)
        new_data = orm.read_data("users")
        print("Data after deletion:", new_data)
    
        # Close the connection
        orm.close_connection()
    Python

    Conclusão

    Em resumo, este ORM exemplifica uma implementação direta dos princípios DRY. Ao utilizar esta abordagem, os desenvolvedores podem reduzir significativamente a complexidade do código e minimizar o número de consultas.

    No entanto, enquanto um ORM simplifica o código e reduz a repetição, esta implementação em particular permanece relativamente simplista em comparação com ORMs mais estabelecidos.

    Por exemplo, ele necessita da inclusão de um BaseModel para criar tabelas inteiramente via código Python. E não tem capacidades para estabelecer relacionamentos de tabela. Ou filtrar dados com base em valores específicos além de retornar todas as linhas.

    No entanto, esta demonstração serve como um vislumbre perspicaz do funcionamento interno dos ORMs em relação às operações de banco de dados.

  • Herança de Templates no Django: Criando Páginas Dinâmicas

    Herança de Templates no Django: Criando Páginas Dinâmicas

    Herança de templates no django é uma funcionalidade que o django template language traz para o framework. Para facilitar e acelerar o desenvolvimento do HTML usando a metodologia DRY – don’t repeat yourself (nao se repita).

    O sistema de template, para trazer uma idéia facilitada, seria como se fosse um lego. Onde você poderá criar uma template como base, outra template para o header, outra template para uma seção de postagens por exemplo, e reultiliza-la em outras templates no django da maneira que você bem entenda.

    Como se fossem componentes resumidamente. Onde unindo-os tornara uma pagina html apenas.

    Nesta postagem eu irei te explicar de forma simples e visual como os sitema de herança de templates funcionam.

    Como funciona a herança de templates no django?

    Antes de te explicar o funcionamento de templates no django eu irei te detalhar como, e o jeito de criar paginas estaticas são. E ao entender esta forma de criar paginas você terá uma idéia do impacto o django template language, quanto irá ajudar o seu desenvolvimento de software.

    Paginas estáticas usando apenas html

    Na imagem acima, eu trouxe um exemplo para facilitar o seu entendimento. No caso, temos uma aplicação simples com quatro paginas. Podemos dizer que a pagina 1 é a pagina home, a pagina 2 seria produtos, a pagina 3 seria contato, e a pagina 4 seria por exemplo uma pagina de formulario.

    Com isso, voce pode perceber, que todas elas se repetem. No minimo todas tem as tags <html> e <body>. Fora que dentro das tags internas e bem provável que essas páginas também tem componentes repetidos como:

    1. Navbar
    2. Sections
    3. Footer

    Imagina, toda vez que tenhamos que criar uma nova pagina, termos que copiar praticamente todo o codigo para ela. Como falei acima, no desenvolvimento, nós precisamos focar em criar coisas novas, e não ficar repetindo o mesmo código. Por isso devemos seguir a metodologia DRY (don’t Repeat Yourself).

    E é aí que as templates do django entram. ;D

    Paginas dinâmicas nas templates no django

    templates no django

    No exemplo acima eu tento te explicar atravez de imagens, de uma forma bem “high level” como templates funcionam no django.

    Nesta imagem, do lado direito, temos a template base (azul), que é comum em todas as outras páginas. Com isso, todas as outras templates poderam herda-las para que o django renderize uma página html única.

    Ja no meio da imagem, temos as templates (verdes) que usaram a template base para usar suas tags como html e body. E por último temos uma outra template (vermelha) que pode ser qualquer código html que possivelmente pode ser usada em qualquer outra parte do código.

    Resumindo:

    • A primeira template (1) pode ser vista como o header da pagina.
    • A segunda template (2) como uma section qualquer.
    • A terceira template (3) e vista como uma sub-section que pode ou nao ser inclusa dentro da template base. Mas foi inicialmente criada para ser usada para se adicionar em uma section.

    Estrutura basica para usar as templates no django

    Você deve estar se perguntando: Mas como tudo isso se une, e como elas são configuradas para criar paginas unicas?

    Essa é uma otima pergunta. Basicamente, no django-template-language as heranças de templates são feitas usando as tags:

    • block
    • extends
    • include

    Usando a tag de template chamada {% block %}

    Eu quero trazer primeiramente a tag {% block %} para que você entenda de uma forma crescente o uso de cada tag na linguagem de template do django.

    Basicamente, a tag {% block %} é usada para definir blocos de conteúdo que podem ser substituídos ou modificados nos templates filhos.

    Em outras palavras, ela é usada como block de abrir e fechar para que as templates filhos sejam inclusas dentro delas. Da mesma forma de que fazemos com html.. Entende?

    Em resumo, a tag {% block %} funciona como um marcador que define áreas específicas do template base onde o conteúdo dos templates filhos será inserido. Pense nela como uma “caixa” que pode ser preenchida ou alterada nas páginas que herdam esse template.

    Exemplo:

    {% block content %}
    <!-- Templates filhos iram ser inclusas aqui -->
    {% endblock %}
    HTML

    Note que a tag {% block %} é acompanhada por uma tag de fechamento {% endblock %}, semelhante a como abrimos e fechamos tags no HTML.

    Como funciona na prática?

    Quando usamos a tag {% extends 'nome_do_template.html' %} em um template filho, ele “herda” a estrutura do template pai. O conteúdo que colocamos entre as tags {% block %} e {% endblock %} no template filho será inserido na “caixa” correspondente no template base.

    Template Base (base.html):

    <!DOCTYPE html>
    <html lang="pt-br">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>{% block title %}Meu Site{% endblock %}</title>
        <link rel="stylesheet" href="{% static 'css/style.css' %}">
    </head>
    <body>
    
        <!-- Cabeçalho que pode ser transformado em uma template -->
        <header>
            <nav>
                <ul>
                    <li><a href="/">Home</a></li>
                    <li><a href="/about/">Sobre</a></li>
                    <li><a href="/contact/">Contato</a></li>
                </ul>
            </nav>
        </header>
    
        <!-- Conteúdo principal -->
        <main>
            {% block content %} 
            <!-- O conteúdo específico da página será inserido aqui -->
            {% endblock %}
        </main>
    
        <!-- Rodapé que pode ser transformado em uma template -->
        <footer>
            <p>© 2024 Meu Site. Todos os direitos reservados.</p>
        </footer>
    
    </body>
    </html>
    HTML

    Template Filho (home.html):

    {% extends "base.html" %}
    
    {% block title %}
      Home - Meu Site
    {% endblock %}
    
    {% block content %}
      <h2>Bem-vindo à página inicial!</h2>
      <p>Este é o conteúdo específico da página inicial.</p>
    {% endblock %}
    
    HTML

    Como visto, o template home.html herda a estrutura do base.html usando a tag {% extends %}.

    Desta forma, a linguagem de template do django, entende que você quer usar a template base.html para inserir o codigo. E entende onde cada bloco da template home.html devem ser inseridos na template base.html.

    Caso voce queira ter uma introdução do django você póde dar uma olhada nessa postagem: 😎
    
    Introdução ao django

    Sendo assim, como se pode ver, temos dois blocks (ou duas caixas que seram inseridas na template base) um e o {% block title %} que esta no topo da template base.html e o segundo e o {% block content %} que será incluso o codigo html.

    Como funciona a tag {% include %} nas templates no django

    A tag {% include %} basicamente faz uma “inclusão” de um arquivo de template dentro de outro. Ela carrega e renderiza o conteúdo do template que você especificar diretamente no local onde a tag é usada. Isso é útil quando você quer compartilhar trechos de código comuns entre várias páginas.

    Exemplo de uso:

    Imagine que você tem um cabeçalho que deseja reutilizar em várias páginas do seu site.

    1 Criando o Template do Cabeçalho (header.html):

    <header>
        <nav>
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/about/">Sobre</a></li>
                <li><a href="/contact/">Contato</a></li>
            </ul>
        </nav>
    </header>
    HTML

    2 Usando a tag {% include %} para reutilizar o cabeçalho:

    <!DOCTYPE html>
    <html lang="pt-br">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Meu Site</title>
    </head>
    <body>
    
        <!-- Incluindo o template do cabeçalho !!! -->
        {% include 'header.html' %}
    
        <main>
            <h1>Bem-vindo ao Meu Site!</h1>
            <p>Este é o conteúdo principal da página.</p>
        </main>
    
        <footer>
            <p>© 2024 Meu Site. Todos os direitos reservados.</p>
        </footer>
    
    </body>
    </html>
    HTML

    Quais são as vantagens de usa a tag {% include %}:

    1. Reutilização: Se você tiver elementos repetitivos, como menus de navegação, rodapés, ou outros componentes, pode simplesmente criar um template separado para eles e incluí-los em várias páginas.
    2. Manutenção mais fácil: Se você precisar alterar o conteúdo de um componente comum (como o menu), só precisa editar o template incluído (header.html, por exemplo), e a mudança será refletida em todas as páginas que o usam.
    3. Componentização: Ajuda a dividir partes do layout em “componentes” menores e reutilizáveis, deixando o código mais modular e organizado.

    Exemplo usando condicionais nas templates no django:

    Você também pode passar variáveis para o template incluído ou usar a tag {% include %} dentro de condições.

    {% include 'menu.html' with user=user %}
    HTML

    Ou você pode renderizar o template condicionalmente:

    {% if user.is_authenticated %}
        {% include 'user_menu.html' %}
    {% else %}
        {% include 'guest_menu.html' %}
    {% endif %}
    
    HTML

    Onde no codigo acima, e checado se o usuario esta autenticado. Se sim retornar a template user_menu.html. Agora, caso o usuario não esteja autenticado retornar a template guest_menu.html.

    O uso é infinito.

    Agora, quais as diferenças entre as tags {% include %} e {% extends %}nas templates no django?

    Caracteristica{% extends %}{% include %}
    ObjetivoHerança de templates o django, criando uma estrutura baseIncluir um trecho de template específico
    UsoPara herdar e sobrescrever blocos de conteúdoPara reutilizar partes comuns de um layout
    EstruturaExige que o template filho tenha uma relação direta com o template pai. O template filho precisa herdar o layout geral e definir blocos específicos de conteúdo.Simplesmente injeta o conteúdo de outro template onde a tag está localizada. Não há herança ou blocos envolvidos.
    ContextoUsada quando você deseja ter uma estrutura hierárquica de templates, com um template base e templates filhos que podem alterar partes específicas.Usada para reutilizar componentes ou pedaços de código que são os mesmos em várias partes do site.
    FlexibilidadeEstrutura mais rígida, pois o layout base é seguido pelo template filhoEstrutura mais flexível, permitindo a inclusão de qualquer template em qualquer parte da página

    Conclusão

    A herança de templates no Django é uma das funcionalidades que mais traz eficiência para o desenvolvimento web, especialmente ao seguir a metodologia DRY (Don’t Repeat Yourself). Como discutido ao longo desta postagem, o sistema de templates do Django permite criar páginas dinâmicas e organizadas, reutilizando estruturas básicas como cabeçalhos, rodapés e seções inteiras de forma modular e facilmente gerenciável.

    Através da tag {% extends %}, conseguimos construir uma página base que serve como um esqueleto para outras páginas, facilitando a inserção de conteúdo específico sem a necessidade de duplicar código. Essa abordagem é comparável a usar “componentes” que formam diferentes partes de uma aplicação web, onde uma única base é usada para gerar múltiplas páginas com pequenas variações de conteúdo.

    A tag {% block %}, por sua vez, nos permite marcar regiões específicas do template base que podem ser alteradas por templates filhos, tornando o processo de substituição de conteúdo simples e direto. Isso garante que áreas essenciais, como menus e rodapés, permaneçam consistentes, enquanto o conteúdo dinâmico é adicionado conforme necessário.

    Além disso, a tag {% include %} oferece uma maneira eficiente de incluir trechos de templates que podem ser reutilizados em diversas partes da aplicação, como menus, formulários e blocos de conteúdo recorrentes. Essa funcionalidade reduz a necessidade de duplicação e permite atualizações rápidas e consistentes em todas as páginas que utilizam esses componentes.

    Em conjunto, o uso de {% extends %}, {% block %} e {% include %} não apenas otimiza o tempo de desenvolvimento, mas também facilita a manutenção e evolução do projeto, mantendo o código mais limpo e fácil de entender. Ao modularizar o layout e separar as responsabilidades entre templates base e filhos, o Django proporciona uma arquitetura flexível, escalável e eficiente para o desenvolvimento de interfaces dinâmicas.

    Com esse sistema, desenvolvedores podem focar no que realmente importa: criar novas funcionalidades e melhorar a experiência do usuário, sem se preocupar com a repetição de código e a complexidade de manutenção do layout.

  • Noções Basicas de Models no Django e Como Usá-los Para Interagir Com o Banco de Dados.

    Noções Basicas de Models no Django e Como Usá-los Para Interagir Com o Banco de Dados.

    Django models são simplemente a definição e representação de dados em uma aplicação Django.

    Com isso, caso você queira trabalhar e implementar interações com algum banco de dados e essencial que você entenda como trabalhar com essa ferramenta no qual ira te ajudar muito no seu desenvolvimento.

    Vamos lá! Irei explicar sobre os models do django de uma forma simplificada, no qual esperofacilitar o seu entendimento.

    Ok, mas o que são django models de uma forma mais técnica?

    Bem, se você ja tem uma noção do que é um banco de dados relacional. Onde existem tabelas especificas que se pode se inserir dados, ficará muito facil te explicar.

    No caso, os models do Django são usados para criar e representar tabelas de um banco de dados como objetos em Python.

    Em outras palavras, você poderá criar um model no Django (que representa uma tabela) herdando uma classe do Django chamada Model.

    Como cada tabela de um banco de dados tem tipos de campos diferentes, você também poderá aplicar essa tipificação aos campos da mesma maneira, porém utilizando o Django.

    Exemplo de uma tabela simples no SQL:

    idtitulodescricao
    1Como fazer molho de tomate caseiroNessa postagem iremos falar sobre um dos…
    210 maneiras de criar massas de pizza caseiraVoce ira aprender quais são as dez maneira…
    3Quais os melhores sistemas de restauranteTrabalhando a 15 anos como gestor de resta..
    Tabela: Postagens

    Agora, como uma tabela seria representada em uma aplicação Django?

    from django.db import models # <-- Herdando toda a lógica pronta do Django
    
    class Postagen(models.Model):
        titulo = models.CharField(max_length=120)
        descricao = models.TextField()
        
        def __str__(self):
          return self.titulo
    Python

    Como podemos notar, temos uma tabela (vamos dizer que é uma tabela em um banco de dados 😄) chamada Postagens. Logo abaixo, temos um model no Django que representa essa tabela com o mesmo número de colunas: título e descrição.

    Ah, só para lembrar que, no Django, não é necessário adicionar o campo ID. Ele é adicionado por padrão nos modelos do Django. 😉

    Dessa forma, com uma explicação um pouco mais técnica que a introdução, você já consegue entender melhor qual é o propósito inicial de um model no Django.

    Campos Comuns Usados em Modelo do Django

    Como existem vários tipos de dados para colunas em um banco de dados, como strings, caracteres, booleanos, numéricos (inteiros, flutuantes e especiais), etc., no próprio model do Django você terá a possibilidade de criar diferentes colunas com diferentes tipos de dados.

    No exemplo acima, vemos duas colunas: título e descrição. Essas duas colunas têm tipos de dados praticamente iguais: CharField() e TextField().

    O CharField traz a capacidade de criar textos com um número limitado de caracteres (no exemplo acima, com 120 caracteres) e será traduzido como VARCHAR no banco de dados.

    Já o TextField é basicamente a representação de uma string, sem limitação de caracteres, e será traduzido como TEXT no banco de dados.

    Além dessas existe uma gama de campos usados em models no Django.

    Porém as mais comuns são os campos:

    1. Para textos temos os CharField (cujo e obrigatorio usar o parametro max_length) e o TextField.
    2. Tipo numéricos temos o IntegerField (que armazena numeros inteiros), FloatField e o DecimalField que tambem adiciona numeros flutuantes porem com casas decimais definidas como a adição de casas decimais com o parametro decimal_places, e o numero total de digitos com o parametro max_digits.
    3. Também temos campos que representam data e hora. Com os campos, DateField que apenas armazena (ano, mes e dia). O TimeField que apenas armazena horas e o DateTimeField que armazen data e horas.
    4. Alem disso também temos campos do tipo booleanos como o BooleanField no qual e usado para adicionar valores como True ou False.
    5. E por fim, temos os campos de relacionamentos: ForeignKey onde se cria um relacionamento de “muitos para um” onde se é necessario adicionar para qual tabela ou modelo esta sendo relacionado e o parametro on_delete no qual será setado o que acontecerá ao deletar a row com o relacionamento. O campo de relacionamento OneToOneField no qual cria um relacionamento de “um para um” entre duas tabelas. E por fim o campo de relacionamento ManyToManyField que criar relacionamentos de “mutos para muitos” entre duas tabelas.

    Os campos citados acima são apenas os mais comuns usados para a criação de um model no django. Existem varios outros no qual voce pode pesquisar para uso mais especificos e tambem pode ate criar um campo especifico para seu uso especifico, porem eu não irei entrar em muitos detalhes nesta postagem.

    Conectando com bancos de dados em uma aplicação django

    Antes de iniciar qualquer explicação aqui sobre a criação de objetos usando a ORM do django através dos models, ficaria sem sentido fazer isso sem a explicação da conexão de uma aplicação django com um banco de dados. Com isso explicarei brevemente como uma conexão do django e feita com o banco de dados:

    Por padrão o django tem um arquivo de configuração chamado settings.py onde vários arquivos de conexão e configurações estão alocadas, e uma delas é a conexão com o banco de dados.

    # settings.py
    
    DATABASES = {
        "default": {
            "ENGINE": "django.db.backends.sqlite3",
            "NAME": "mydatabase",
        }
    }
    Python

    No código acima podemos ver qual é a constante que representa a conexão com o banco de dados chamada DATABASES. Neste exemplo é representado com uma configuração padrão de uma aplicação inicial do Django.

    Por outro lado, também podemos usar esta mesma constante para se conectar com diferente bancos de dados:

    # settings.py
    
    DATABASES = {
        "default": {
            "ENGINE": "django.db.backends.postgresql",
            "NAME": "mydatabase",
            "USER": "mydatabaseuser",
            "PASSWORD": "mypassword",
            "HOST": "127.0.0.1",
            "PORT": "5432",
        }
    }
    Python

    Com o exemplo acima criando a conexão com um banco de dados “ENGINE” postgresql e suas variaveis necessarias para conexão.

    Migrando as Tabelas

    Quando você define os models (modelos de dados) no Django, eles ainda não existem no banco de dados. Para criar as tabelas no banco, você usa o comando python manage.py migrate. O Django então traduz os models em tabelas SQL e as cria no banco de dados.

    Realizando a Conexão

    Quando você executa o Django (comandos como runserver ou migrate), o Django usa essas informações para se conectar ao banco de dados. Ele cria uma conexão automática por meio de sua camada de abstração de banco de dados, chamada ORM (Object-Relational Mapping). Com o ORM, o Django traduz o código Python em consultas SQL para interagir com o banco de dados.

    Interagindo com o Banco de Dados

    Com a conexão estabelecida, o Django permite que você faça operações como criar, ler, atualizar e deletar registros no banco de dados usando código Python. Basicamente, Você não precisa escrever consultas SQL manualmente, o Django faz isso por você com seu ORM.

    Passo-a-passo de iteração com banco de dados usando django models e ORM

    Vamos supor que iremos criar uma aplicação django onde iremos adicionar postagens (da mesma maneira que fizemos no topo desta postagem). Porém iremos usar esta tabela para iteragir com o banco de dados.

    # models.py
    from django.db import models
    from django.contrib.auth.models import User
    
    class Postagem(models.Model):
        titulo = models.CharField(max_length=120)
        descricao = models.TextField()
        data_criacao = models.DateField(auto_now_add=True)
        autor = models.ForeignKey(User, on_delete=models.DO_NOTHING)
        
        def __str__(self):
            return self.titulo
    Python

    Ao criar esta tabela devemos rodar o comando:

    python manage.py makemigrations # cria um arquivo de migrations
    python manage.py migrate # reflete o model no banco de dados
    Bash

    Ao ativar os dois comandos acima, por padrão, será criado um banco de dados sqlite3 no django (em caso você não fazer conexão com outro banco de dados). É refletida todas as migrations padrão do django e a desse modelo para o banco de dados.

    Interagindo Com o Banco de Dados Usando ORM do Django

    Agora que temos toda configuração feita podemos testar nosso modelo de postagens em usuarios usando o ORM do django.

    No terminal adicione o seguinte comando:

    python manage.py shell
    Bash

    Com isso voce terá acesso ao shell da aplicação django que voce esta trabalhando. Então se tudo correu bem você terá acesso ao shell da aplicação como a seguir:

    (venv) C:\software_projects\projeto_de_configuração> python manage.py shell
    Python 3.10.11 (...) [MSC v.1929 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> # seu codigo ira ser adicionado aqui
    Bash

    Agora vamos iniciar a criação dos dados usando os models que criamos e a ORM do django.

    >>> # imports
    >>> from postagens.models import Postagem       
    >>> from django.contrib.auth.models import User
    >>> 
    >>> # criação de usuario --
    >>> user = User.objects.create(username="Elias", password="Aprendendo123")
    >>> 
    >>> # testando se usuario foi criado
    >>> user
    <User: Elias>
    >>>
    >>> # criacao de postagem --
    >>> postagem = Postagem.objects.create(
    ... titulo="Noções Basicas de Models no Django..",
    ... descricao="Models é simplemente a definição e representação de dados em...",
    ... autor=user
    ... )
    >>> # checagem se a postagem foi criada
    >>> postagem
    <Postagem: Noções Basicas de Models no Django..>
    >>>
    >>> # checagem de campos.     
    >>> postagem.autor
    <User: Elias>
    >>> postagem.data_criacao
    datetime.date(2024, 9, 27)
    >>>
    Python

    Como vemos acima, usamos um sub-framework do Django ORM para interagir com o banco de dados. Explicando o que foi feito: assim que entrei no shell com o comando python manage.py shell, fiz o import dos models que irei usar, o model Postagem e o User (que é padrão do Django).

    Em seguida, foi usado o comando para criar um único usuário com apenas username e password. Só para lembrar que foi criado o usuário porque seria necessário para a criação de uma postagem.

    Sem um usuário, não seria possível criar uma postagem. Dessa forma, a postagem foi criada, associando o usuário criado anteriormente ao campo autor.

    Por último, foi verificado se a postagem havia sido criada corretamente, também checando os campos como postagem.autor e postagem.data_criacao.

    Checando Os Dados Diretamente No Banco de Dados

    Caso você esteja usando o VSCode, poderá instalar uma extensão chamada SQLite Viewer.

    Com essa extensão você poderá acessar o banco de dados de teste sqlite clicando no icone do sqlite para acessar os dados que foram criados usando os comandos do shell.

    Como voce vê acima, para visualizar as tabelas criadas você poderá seguir os passos que foram feitos acima (logo após você instalar o SQLite Viewer).

    1. Então nesse caso, você poderá iniciar clicando no icone do banco db.sqlite3.
    2. Ja na sequência você terá acesso a todas as tabelas que existem no sistema.
    3. Ache a tabela que precisa saber onde estão os dados criados (lembrando que o django segue um padrão de nomeação de tabelas (<app-name>_<model-name>)). Então nesse caso precisa-se clicar em postagens_postagem.
    4. Ao clicar na tabela você terá o acesso aos dados que você criou com os dados como id, titulo, descricao, data_criacao e autor_id.

    Conclusão

    Nesta postagem poderia ser explicado tudo que sei sobre ORM, como criação de diferente relacionamentos, criação de campos customizaveis ou até mesmo te explicar outros tipos de campos como o JSONField() porém o foco é você entender as noções basicas de models no django.

    Nesta postagem eu gostaria apenas de te apresentar como podemos trabalhar com models de uma forma simples e se conectar com o banco, criando alguns objetos, com inserção dos dados no banco de dados.

    Caso você precise de uma postagem mais complexa futuramente irei iniciar uma postagem com detalhes a fundo de django ORM, olhando por de baixo do capô do django e entendendo como esse framework funciona por de baixo dos panos.