Dominando a Camada de Modelos (ORM) no Django

A camada de modelos do Django é a abstração que permite interagir com o banco de dados de forma orientada a objetos, sem a necessidade de escrever SQL diretamente. Cada aplicação Django (app) define seus modelos no arquivo models.py, que representam as tabelas do banco de dados.

  1. Configuração do Ambiente de Teste

Para testar funcionalidades do Django ORM sem a necessidade de um servidor web completo, podemos criar um script de teste autônomo. Isso é particularmente útil para depuração e para validar a lógica dos modelos.

Preparação do Ambiente

  1. Crie um arquivo Python (pode ser tests.py no seu app ou um arquivo separado) com um ponto de entrada if __name__ == '__main__':.
  2. Importe o módulo os e configure a variável de ambiente DJANGO_SETTINGS_MODULE para apontar para o arquivo de configurações do seu projeto.
  3. Importe o módulo django e chame django.setup() para inicializar o ambiente do Django.
import os
import django

# Certifica-se de que o Django está configurado para o ambiente do projeto
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'meuprojeto.settings') # Substitua 'meuprojeto' pelo nome do seu projeto

    django.setup()

    # O código de teste do ORM deve ser escrito aqui, após a inicialização do Django
    # Exemplo de importação de modelo após setup:
    # from aplicacao.models import Pessoa
    # ...seu código de teste...

Qualquer código de teste que interaja com o ORM deve ser colocado após a chamada django.setup().

  1. Preparação dos Dados e Modelos

2.1 Configuração do Banco de Dados

Para usar o MySQL, é necessário ajustar as configurações do banco de dados no arquivo settings.py do seu projeto. Crie um banco de dados MySQL chamado base_dados_projeto (ou outro nome de sua preferência).

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Motor de banco de dados MySQL
        'NAME': 'base_dados_projeto',         # Nome do seu banco de dados
        'USER': 'root',                       # Seu usuário do MySQL
        'PASSWORD': 'sua_senha_mysql',        # Sua senha do MySQL
        'HOST': '127.0.0.1',                  # IP do servidor MySQL
        'PORT': 3306,                         # Porta do MySQL
        'OPTIONS': {'charset': 'utf8mb4'},    # Opcional: define o charset
    }
}

Além disso, adicione o seguinte patch no arquivo __init__.py do seu projeto para garantir a compatibilidade com pymysql:

import pymysql
pymysql.install_as_MySQLdb()

2.2 Definição de Modelos

No arquivo models.py de sua aplicação (por exemplo, aplicacao/models.py), defina as classes que representam suas tabelas:

from django.db import models

class Pessoa(models.Model):
    nome_completo = models.CharField(max_length=100, verbose_name='Nome Completo')
    idade = models.IntegerField(verbose_name='Idade')
    data_cadastro = models.DateTimeField(auto_now_add=True, verbose_name='Data de Cadastro')
    ultima_atualizacao = models.DateTimeField(auto_now=True, verbose_name='Última Atualização')

    class Meta:
        db_table = 'registros_pessoas' # Nome da tabela no banco de dados
        verbose_name = 'Pessoa'
        verbose_name_plural = 'Pessoas'

    def __str__(self):
        return self.nome_completo

Observações sobre os campos de data e hora:

  • auto_now_add=True: O campo é preenchido automaticamente com a data e hora atuais apenas na primeira vez que o objeto é criado. Não é atualizado em modificações posteriores. Ideal para campos como "criado_em".
  • auto_now=True: O campo é automaticamente atualizado para a data e hora atuais cada vez que o objeto é salvo (tanto na criação quanto na atualização). Perfeito para campos como "ultima_modificacao".

2.3 Migrações do Banco de Dados

Após definir ou modificar seus modelos, você precisa gerar e aplicar as migrações para refletir essas alterações no banco de dados.

python manage.py makemigrations
python manage.py migrate

  1. Operações CRUD com ORM

O Django ORM oferece métodos intuitivos para realizar as operações básicas de Criar, Ler, Atualizar e Deletar (CRUD).

import os
import django

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'meuprojeto.settings')
    django.setup()

    from aplicacao.models import Pessoa # Importe seu modelo após django.setup()

    # ------------------
    # 3.1 Criar Dados (Create)
    # ------------------

    # Método 1: Criação direta usando .create()
    Pessoa.objects.create(nome_completo='Maria Silva', idade=28)
    Pessoa.objects.create(nome_completo='João Souza', idade=35)
    Pessoa.objects.create(nome_completo='Ana Paula', idade=22)

    # Método 2: Instanciar e salvar
    nova_pessoa = Pessoa(nome_completo='Pedro Santos', idade=40)
    nova_pessoa.save()

    print("--- Pessoas criadas ---")

    # ------------------
    # 3.2 Ler Dados (Retrieve)
    # ------------------

    # Recuperar todos os registros
    todas_pessoas = Pessoa.objects.all()
    print("\n--- Todas as pessoas ---")
    for p in todas_pessoas:
        print(f"ID: {p.id}, Nome: {p.nome_completo}, Idade: {p.idade}")

    # Filtrar registros com .filter() (retorna um QuerySet)
    pessoas_jovens = Pessoa.objects.filter(idade__lt=30)
    print("\n--- Pessoas com menos de 30 anos ---")
    for p in pessoas_jovens:
        print(f"ID: {p.id}, Nome: {p.nome_completo}, Idade: {p.idade}")

    # Recuperar um único registro com .get() (lança exceção se não encontrar ou encontrar múltiplos)
    try:
        pessoa_maria = Pessoa.objects.get(nome_completo='Maria Silva')
        print(f"\n--- Pessoa Maria Silva encontrada ---")
        print(f"ID: {pessoa_maria.id}, Nome: {pessoa_maria.nome_completo}, Idade: {pessoa_maria.idade}")
    except Pessoa.DoesNotExist:
        print("Maria Silva não encontrada.")
    except Pessoa.MultipleObjectsReturned:
        print("Múltiplas Marias Silvas encontradas.")

    # Comparativo filter() vs get():
    # | Característica     | filter()                          | get()                               |
    # |--------------------|-----------------------------------|-------------------------------------|
    # | Retorno            | QuerySet (pode ser vazio)         | Único objeto do modelo              |
    # | Quantidade         | 0, 1 ou muitos registros          | Exatamente 1 registro               |
    # | Não encontrado     | QuerySet vazio []                 | Lança DoesNotExist                  |
    # | Múltiplos achados  | QuerySet com múltiplos registros  | Lança MultipleObjectsReturned       |
    # | Encadear consultas | Sim (ex: .filter().order_by())    | Não (retorna um objeto diretamente) |

    # ------------------
    # 3.3 Atualizar Dados (Update)
    # ------------------

    # Método 1: Atualização direta em um QuerySet
    # Atualiza todas as pessoas com idade 35 para 36
    Pessoa.objects.filter(idade=35).update(idade=36, nome_completo='João da Silva Atualizado')
    print("\n--- Pessoa com 35 anos atualizada ---")
    print(Pessoa.objects.get(nome_completo='João da Silva Atualizado').idade)

    # Método 2: Recuperar, modificar e salvar um objeto
    pessoa_pedro = Pessoa.objects.get(nome_completo='Pedro Santos')
    pessoa_pedro.idade = 41
    pessoa_pedro.save() # É crucial chamar .save() para persistir as mudanças
    print(f"--- Pedro Santos atualizado: Idade {pessoa_pedro.idade} ---")

    # Nota: Apenas chamadas a .save() em instâncias de modelo ativam o auto_now=True.
    # O método .update() em QuerySets não aciona auto_now=True por padrão para a data de atualização.

    # ------------------
    # 3.4 Excluir Dados (Delete)
    # ------------------

    # Método 1: Excluir diretamente um QuerySet
    Pessoa.objects.filter(nome_completo='Ana Paula').delete()
    print("\n--- Ana Paula deletada ---")
    print(f"Total de pessoas após exclusão: {Pessoa.objects.count()}")

    # Método 2: Recuperar e deletar um objeto
    try:
        pessoa_a_deletar = Pessoa.objects.get(nome_completo='Maria Silva')
        pessoa_a_deletar.delete()
        print("--- Maria Silva deletada ---")
    except Pessoa.DoesNotExist:
        print("Maria Silva já foi deletada ou não existe.")

    print(f"Total de pessoas no final: {Pessoa.objects.count()}")


  1. Métodos Avançados de Consulta

import os
import django

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'meuprojeto.settings')
    django.setup()

    from aplicacao.models import Pessoa

    # Adicionar algumas pessoas para testes
    Pessoa.objects.all().delete() # Limpa a tabela para um teste limpo
    Pessoa.objects.create(nome_completo='Alice', idade=25)
    Pessoa.objects.create(nome_completo='Bob', idade=30)
    Pessoa.objects.create(nome_completo='Alice', idade=25) # Duplicata para distinct
    Pessoa.objects.create(nome_completo='Carlos', idade=35)
    Pessoa.objects.create(nome_completo='Diana', idade=30)
    Pessoa.objects.create(nome_completo='Eve', idade=40)

    print("--- Dados iniciais para consultas ---")
    for p in Pessoa.objects.all().order_by('id'):
        print(f"ID: {p.id}, Nome: {p.nome_completo}, Idade: {p.idade}, Cadastro: {p.data_cadastro.strftime('%Y-%m-%d %H:%M:%S')}")

    # 4.1 values() e values_list()
    # Retorna um QuerySet de dicionários, com chaves sendo os nomes dos campos
    nomes_e_idades = Pessoa.objects.values('nome_completo', 'idade')
    print("\n--- Nomes e Idades (values) ---")
    for item in nomes_e_idades:
        print(item) # {'nome_completo': 'Alice', 'idade': 25}

    # Retorna um QuerySet de tuplas, com os valores na ordem especificada
    nomes_apenas = Pessoa.objects.values_list('nome_completo')
    print("\n--- Nomes Apenas (values_list) ---")
    for item in nomes_apenas:
        print(item) # ('Alice',)

    # 4.2 distinct() - Remover duplicatas
    # Para que distinct funcione efetivamente, geralmente se usa com values() ou values_list()
    # e sem o campo de chave primária, que é sempre único.
    nomes_distintos = Pessoa.objects.values_list('nome_completo', flat=True).distinct()
    print("\n--- Nomes Distintos ---")
    print(list(nomes_distintos)) # ['Alice', 'Bob', 'Carlos', 'Diana', 'Eve']

    # 4.3 order_by() - Ordenar resultados
    # Ordena por idade crescente
    ordenado_idade_asc = Pessoa.objects.order_by('idade').values('nome_completo', 'idade')
    print("\n--- Ordenado por Idade (ASC) ---")
    print(list(ordenado_idade_asc))

    # Ordena por idade decrescente
    ordenado_idade_desc = Pessoa.objects.order_by('-idade').values('nome_completo', 'idade')
    print("\n--- Ordenado por Idade (DESC) ---")
    print(list(ordenado_idade_desc))

    # 4.4 reverse() - Inverte a ordem de um QuerySet já ordenado
    # Importante: reverse() só funciona em QuerySets que já foram ordenados.
    reverso_idade_asc = Pessoa.objects.order_by('idade').values('nome_completo', 'idade').reverse()
    print("\n--- Revertido de Idade (ASC) ---")
    print(list(reverso_idade_asc)) # Agora será decrescente

    # 4.5 count() - Contar o número de registros
    total_registros = Pessoa.objects.count()
    print(f"\n--- Total de registros: {total_registros} ---")

    # 4.6 exclude() - Excluir registros que correspondem a uma condição
    nao_alice = Pessoa.objects.exclude(nome_completo='Alice').values('nome_completo', 'idade')
    print("\n--- Pessoas que não são Alice ---")
    print(list(nao_alice))

    # 4.7 exists() - Verificar se algum registro existe
    existe_bob = Pessoa.objects.filter(nome_completo='Bob').exists()
    print(f"\n--- Existe Bob? {existe_bob} ---")

    existe_fernanda = Pessoa.objects.filter(nome_completo='Fernanda').exists()
    print(f"--- Existe Fernanda? {existe_fernanda} ---")

    # 4.8 .query - Visualizar a consulta SQL gerada
    # Método 1: Usando .query em um QuerySet
    consulta_sql = Pessoa.objects.filter(idade__gt=30).query
    print(f"\n--- SQL gerado para idade > 30 ---")
    print(consulta_sql)

    # Método 2: Configurando o LOGGING no settings.py (para ver todas as queries)
    # Adicione a seguinte configuração ao seu settings.py para ver o SQL no console:
    # LOGGING = {
    #     'version': 1,
    #     'disable_existing_loggers': False,
    #     'handlers': {
    #         'console':{
    #             'level':'DEBUG',
    #             'class':'logging.StreamHandler',
    #         },
    #     },
    #     'loggers': {
    #         'django.db.backends': {
    #             'handlers': ['console'],
    #             'propagate': True,
    #             'level':'DEBUG',
    #         },
    #     }
    # }

  1. Consultas com Notação de Duplo Sublinhado (Field Lookups)

Os "field lookups" permitem realizar consultas mais complexas nos campos do modelo.

import os
import django
from datetime import datetime

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'meuprojeto.settings')
    django.setup()

    from aplicacao.models import Pessoa

    # Adicionar dados para os exemplos
    Pessoa.objects.all().delete()
    Pessoa.objects.create(nome_completo='Zacarias', idade=20, data_cadastro=datetime(2023, 1, 10, 10, 0, 0))
    Pessoa.objects.create(nome_completo='Xavier', idade=25, data_cadastro=datetime(2023, 1, 15, 11, 30, 0))
    Pessoa.objects.create(nome_completo='Wesley', idade=30, data_cadastro=datetime(2023, 2, 1, 12, 0, 0))
    Pessoa.objects.create(nome_completo='Yara', idade=35, data_cadastro=datetime(2023, 2, 5, 13, 45, 0))
    Pessoa.objects.create(nome_completo='Vanessa', idade=40, data_cadastro=datetime(2023, 3, 1, 14, 0, 0))
    Pessoa.objects.create(nome_completo='zeus', idade=20, data_cadastro=datetime(2023, 3, 10, 15, 20, 0))


    print("\n--- Consultas com Duplo Sublinhado ---")

    # 5.1 Maior que (Greater Than) - __gt
    maior_que_25 = Pessoa.objects.filter(idade__gt=25).values('nome_completo', 'idade')
    print(f"Pessoas com idade > 25: {list(maior_que_25)}")

    # 5.2 Maior ou igual a (Greater Than Equal) - __gte
    maior_ou_igual_30 = Pessoa.objects.filter(idade__gte=30).values('nome_completo', 'idade')
    print(f"Pessoas com idade >= 30: {list(maior_ou_igual_30)}")

    # 5.3 Menor que (Less Than) - __lt
    menor_que_30 = Pessoa.objects.filter(idade__lt=30).values('nome_completo', 'idade')
    print(f"Pessoas com idade < 30: {list(menor_que_30)}")

    # 5.4 Menor ou igual a (Less Than Equal) - __lte
    menor_ou_igual_20 = Pessoa.objects.filter(idade__lte=20).values('nome_completo', 'idade')
    print(f"Pessoas com idade <= 20: {list(menor_ou_igual_20)}")

    # 5.5 In (em uma lista de valores) - __in
    idades_especificas = Pessoa.objects.filter(idade__in=[20, 40]).values('nome_completo', 'idade')
    print(f"Pessoas com idade 20 ou 40: {list(idades_especificas)}")

    # 5.6 Range (intervalo inclusivo) - __range
    idade_entre_20_30 = Pessoa.objects.filter(idade__range=[20, 30]).values('nome_completo', 'idade')
    print(f"Pessoas com idade entre 20 e 30: {list(idade_entre_20_30)}")

    # 5.7 Contém (case-sensitive) - __contains
    nomes_com_s = Pessoa.objects.filter(nome_completo__contains='es').values('nome_completo')
    print(f"Nomes que contêm 'es' (case-sensitive): {list(nomes_com_s)}")

    # 5.8 Contém (case-insensitive) - __icontains
    nomes_com_za_ignorar_maiusculas = Pessoa.objects.filter(nome_completo__icontains='za').values('nome_completo')
    print(f"Nomes que contêm 'za' (case-insensitive): {list(nomes_com_za_ignorar_maiusculas)}")

    # 5.9 Começa com (Starts With) - __startswith
    nomes_comecam_com_w = Pessoa.objects.filter(nome_completo__startswith='W').values('nome_completo')
    print(f"Nomes que começam com 'W': {list(nomes_comecam_com_w)}")

    # 5.10 Termina com (Ends With) - __endswith
    nomes_terminam_com_a = Pessoa.objects.filter(nome_completo__endswith='a').values('nome_completo')
    print(f"Nomes que terminam com 'a': {list(nomes_terminam_com_a)}")

    # 5.11 Consultas de Data/Hora
    # Filtrar por mês
    cadastro_janeiro = Pessoa.objects.filter(data_cadastro__month=1).values('nome_completo', 'data_cadastro')
    print(f"Cadastros em Janeiro: {list(cadastro_janeiro)}")

    # Filtrar por dia
    cadastro_dia_1 = Pessoa.objects.filter(data_cadastro__day=1).values('nome_completo', 'data_cadastro')
    print(f"Cadastros no dia 1: {list(cadastro_dia_1)}")

    # Filtrar por hora
    cadastro_hora_10 = Pessoa.objects.filter(data_cadastro__hour=10).values('nome_completo', 'data_cadastro')
    print(f"Cadastros na hora 10: {list(cadastro_hora_10)}")

  1. Operações com Relacionamentos de Modelos

O Django ORM facilita o gerenciamento de relacionamentos entre tabelas (modelos) como Um para Muitos, Muitos para Muitos e Um para Um.

6.1 Definição de Relacionamentos

  • Um para Muitos (ForeignKey): O campo de chave estrangeira é definido no modelo que representa o lado "muitos" do relacionamento. Exemplo: Um Livro tem uma Editora, mas uma Editora pode ter muitos Livros. O ForeignKey fica em Livro. É obrigatório o parâmetro on_delete.
  • Muitos para Muitos (ManyToManyField): Usado quando múltiplos objetos de um modelo podem se relacionar com múltiplos objetos de outro modelo. Exemplo: Um Livro pode ter vários Autores, e um Autor pode escrever vários Livros. O Django cria automaticamente uma tabela intermediária para gerenciar essa relação. Não usa on_delete.
  • Um para Um (OneToOneField): Cada objeto de um modelo está ligado a exatamente um objeto de outro modelo. Exemplo: Um Autor pode ter apenas um DetalheAutor e vice-versa. O campo OneToOneField pode ser colocado em qualquer um dos modelos, mas é comum colocá-lo no modelo que é mais frequentemente consultado. É obrigatório o parâmetro on_delete.

Parâmetros chave para campos de relacionamento:

  • to: Especifica o modelo ao qual o campo se relacinoa.
  • on_delete: (Apenas para ForeignKey e OneToOneField) Define o comportamento quando o objeto referenciado é excluído (ex: models.CASCADE para exclusão em cascata).

Exemplo de Modelos com Relacionamentos (aplicacao/models.py)

from django.db import models

class Editora(models.Model):
    nome_editora = models.CharField(max_length=50, verbose_name='Nome da Editora')
    localizacao = models.CharField(max_length=100, verbose_name='Localização')

    class Meta:
        db_table = 'editoras'
        verbose_name = 'Editora'
        verbose_name_plural = 'Editoras'

    def __str__(self):
        return self.nome_editora

class DetalheAutor(models.Model):
    telefone_contato = models.BigIntegerField(verbose_name='Telefone de Contato')
    endereco_residencia = models.CharField(max_length=100, verbose_name='Endereço de Residência')

    class Meta:
        db_table = 'detalhes_autores'
        verbose_name = 'Detalhe do Autor'
        verbose_name_plural = 'Detalhes dos Autores'

    def __str__(self):
        return f"Detalhe de {self.telefone_contato}"

class Autor(models.Model):
    nome_autor = models.CharField(max_length=50, verbose_name='Nome do Autor')
    data_nascimento = models.DateField(verbose_name='Data de Nascimento', null=True, blank=True)
    # Relacionamento Um para Um com DetalheAutor
    info_adicional = models.OneToOneField(to='DetalheAutor', on_delete=models.CASCADE, verbose_name='Informações Adicionais')

    class Meta:
        db_table = 'autores'
        verbose_name = 'Autor'
        verbose_name_plural = 'Autores'

    def __str__(self):
        return self.nome_autor

class Livro(models.Model):
    titulo = models.CharField(max_length=100, verbose_name='Título do Livro')
    preco = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='Preço')
    data_publicacao = models.DateTimeField(auto_now_add=True, verbose_name='Data de Publicação')
    # Relacionamento Um para Muitos com Editora
    editora = models.ForeignKey(to='Editora', on_delete=models.CASCADE, verbose_name='Editora')
    # Relacionamento Muitos para Muitos com Autor
    autores = models.ManyToManyField(to='Autor', verbose_name='Autores')

    class Meta:
        db_table = 'livros'
        verbose_name = 'Livro'
        verbose_name_plural = 'Livros'

    def __str__(self):
        return self.titulo

Após criar esses modelos, execute novamente makemigrations e migrate.

6.2 Operações CRUD com Chaves Estrangeiras (Um para Muitos)

Vamos adicionar e manipular livros e editoras.

import os
import django
from datetime import date

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'meuprojeto.settings')
    django.setup()

    from aplicacao import models

    # Limpar dados existentes para um teste limpo
    models.Livro.objects.all().delete()
    models.Editora.objects.all().delete()
    models.Autor.objects.all().delete()
    models.DetalheAutor.objects.all().delete()

    # Adicionar Editoras Base
    editora_a = models.Editora.objects.create(nome_editora='Editora Alfa', localizacao='São Paulo')
    editora_b = models.Editora.objects.create(nome_editora='Editora Beta', localizacao='Rio de Janeiro')
    editora_c = models.Editora.objects.create(nome_editora='Editora Gama', localizacao='Belo Horizonte')

    # -----------------------------------------------
    # 6.2.1 Adicionar Livros (com Chave Estrangeira)
    # -----------------------------------------------

    # Método 1: Usando o ID da chave estrangeira (editora_id)
    livro1 = models.Livro.objects.create(titulo='O Código Secreto', preco=45.00, editora_id=editora_a.id)

    # Método 2: Usando a instância do objeto relacionado (editora)
    livro2 = models.Livro.objects.create(titulo='A Teia do Destino', preco=55.50, editora=editora_b)

    print("\n--- Livros Criados (Um para Muitos) ---")
    for livro in models.Livro.objects.all():
        print(f"Livro: {livro.titulo}, Editora: {livro.editora.nome_editora}") # Acessando a editora diretamente

    # -----------------------------------------------
    # 6.2.2 Modificar Livros (Chave Estrangeira)
    # -----------------------------------------------

    # Método 1: Atualizando o ID da chave estrangeira diretamente
    models.Livro.objects.filter(id=livro1.id).update(editora_id=editora_c.id)
    print(f"\n--- Livro '{livro1.titulo}' atualizado para Editora: {models.Livro.objects.get(id=livro1.id).editora.nome_editora} ---")

    # Método 2: Atualizando com a instância do objeto relacionado
    models.Livro.objects.filter(id=livro2.id).update(editora=editora_a)
    print(f"--- Livro '{livro2.titulo}' atualizado para Editora: {models.Livro.objects.get(id=livro2.id).editora.nome_editora} ---")

    # -----------------------------------------------
    # 6.2.3 Excluir Editora (e Livros relacionados devido ao CASCADE)
    # -----------------------------------------------

    # Se editora_a for excluída, todos os livros que referenciam editora_a também serão excluídos (CASCADE)
    editora_a_id = editora_a.id
    editora_a.delete()
    print(f"\n--- Editora {editora_a.nome_editora} (ID: {editora_a_id}) excluída ---")
    print(f"Livros restantes: {list(models.Livro.objects.values_list('titulo', flat=True))}")
    # Note que livro1 e livro2, que agora apontavam para editora_a, foram excluídos.

6.3 Operações CRUD com Chaves Estrangeiras (Muitos para Muitos)

O relacionamento Muitos para Muitos entre Livro e Autor cria uma tabela intermediária automaticamente. Não podemos operar diretamente nesta tabela, mas sim através dos campos de relacionamento nos objetos.

import os
import django
from datetime import date

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'meuprojeto.settings')
    django.setup()

    from aplicacao import models

    # Limpar dados existentes para um teste limpo (se já não o fez)
    models.Livro.objects.all().delete()
    models.Editora.objects.all().delete()
    models.Autor.objects.all().delete()
    models.DetalheAutor.objects.all().delete()

    # Preparar dados base
    editora_unica = models.Editora.objects.create(nome_editora='Editora Principal', localizacao='Salvador')
    detalhe_a = models.DetalheAutor.objects.create(telefone_contato=987654321, endereco_residencia='Rua A, 123')
    detalhe_b = models.DetalheAutor.objects.create(telefone_contato=123456789, endereco_residencia='Rua B, 456')
    detalhe_c = models.DetalheAutor.objects.create(telefone_contato=112233445, endereco_residencia='Rua C, 789')

    autor1 = models.Autor.objects.create(nome_autor='Camilo', data_nascimento=date(1980, 5, 15), info_adicional=detalhe_a)
    autor2 = models.Autor.objects.create(nome_autor='Brenda', data_nascimento=date(1990, 8, 20), info_adicional=detalhe_b)
    autor3 = models.Autor.objects.create(nome_autor='Daniel', data_nascimento=date(1975, 2, 10), info_adicional=detalhe_c)

    livro_ficcao = models.Livro.objects.create(titulo='Crônicas de Um Sonho', preco=60.00, editora=editora_unica)
    livro_aventura = models.Livro.objects.create(titulo='O Caminho do Explorador', preco=75.00, editora=editora_unica)
    livro_poesia = models.Livro.objects.create(titulo='Versos Silenciosos', preco=30.00, editora=editora_unica)

    # -----------------------------------------------
    # 6.3.1 Adicionar Autores a Livros (Muitos para Muitos) - .add()
    # -----------------------------------------------
    # Adicionar um único autor a um livro
    livro_ficcao.autores.add(autor1)
    print(f"\n--- Autores de '{livro_ficcao.titulo}': {[a.nome_autor for a in livro_ficcao.autores.all()]} ---")

    # Adicionar múltiplos autores a um livro (por ID ou instância)
    livro_aventura.autores.add(autor1.id, autor2)
    print(f"--- Autores de '{livro_aventura.titulo}': {[a.nome_autor for a in livro_aventura.autores.all()]} ---")

    # -----------------------------------------------
    # 6.3.2 Modificar Autores de Livros (Muitos para Muitos) - .set()
    # -----------------------------------------------
    # Substitui todos os autores existentes por uma nova lista
    livro_ficcao.autores.set([autor2, autor3]) # Agora Livro Ficção terá Brenda e Daniel
    print(f"\n--- Autores de '{livro_ficcao.titulo}' (após set): {[a.nome_autor for a in livro_ficcao.autores.all()]} ---")

    # É possível usar IDs também
    livro_aventura.autores.set([autor3.id]) # Livro Aventura terá apenas Daniel
    print(f"--- Autores de '{livro_aventura.titulo}' (após set): {[a.nome_autor for a in livro_aventura.autores.all()]} ---")

    # -----------------------------------------------
    # 6.3.3 Remover Autores de Livros (Muitos para Muitos) - .remove()
    # -----------------------------------------------
    # Remover um único autor
    livro_ficcao.autores.remove(autor2) # Remove Brenda de Livro Ficção
    print(f"\n--- Autores de '{livro_ficcao.titulo}' (após remove Brenda): {[a.nome_autor for a in livro_ficcao.autores.all()]} ---")

    # Remover múltiplos autores (por ID ou instância)
    livro_aventura.autores.remove(autor3) # Remove Daniel de Livro Aventura
    print(f"--- Autores de '{livro_aventura.titulo}' (após remove Daniel): {[a.nome_autor for a in livro_aventura.autores.all()]} ---")

    # -----------------------------------------------
    # 6.3.4 Limpar todos os Autores de um Livro - .clear()
    # -----------------------------------------------
    livro_poesia.autores.add(autor1, autor2, autor3)
    print(f"\n--- Autores de '{livro_poesia.titulo}' (antes clear): {[a.nome_autor for a in livro_poesia.autores.all()]} ---")
    livro_poesia.autores.clear() # Remove todos os autores associados a este livro
    print(f"--- Autores de '{livro_poesia.titulo}' (após clear): {[a.nome_autor for a in livro_poesia.autores.all()]} ---")

Tags: Django ORM Modelos Python BancoDeDados

Publicado em 7-4 04:54