Relacionamento Um-para-Muitos (One-to-Many) no Django
O relacionamento Um-para-Muitos ocorre quando uma entidade principal pode estar associada a várias entidades dependentes. No Django, esse tipo de relacionamento é definido com um campo ForeignKey
na model dependente, apontando para a model principal. Um exemplo clássico é uma empresa que pode fabricar vários produtos:
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=30)
class Product(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE)
name = models.CharField(max_length=30)
price = models.IntegerField()
Nesse caso, o modelo Company
representa um fabricante e é a entidade principal, enquanto o modelo Product
representa um produto e é a entidade dependente.
O campo company
em Product
é um ForeignKey
, que estabelece a relação com Company
. O primeiro argumento define a model associada, e o parâmetro on_delete
determina o comportamento quando um registro da entidade principal é excluído. Algumas opções disponíveis para on_delete
são:
models.CASCADE
: exclui automaticamente os registros dependentes quando a entidade principal é removida.models.PROTECT
: impede a exclusão de um registro da entidade principal se houver registros dependentes vinculados a ele.models.SET_NULL
: define o campo como NULL quando o registro associado na entidade principal é removido. Para isso, o campoForeignKey
deve permitir valores NULL.models.SET_DEFAULT
: atribui um valor padrão ao campoForeignKey
quando a entidade principal é excluída. O campo deve ter um valor padrão definido.models.DO_NOTHING
: não executa nenhuma ação ao excluir a entidade principal, o que pode levar a violações de integridade referencial no banco de dados.
Após realizar a migração em um banco de dados SQLite, as seguintes tabelas serão criadas:
CREATE TABLE "hello_company" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(30) NOT NULL
);
CREATE TABLE "hello_product" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(30) NOT NULL,
"price" integer NOT NULL,
"company_id" bigint NOT NULL REFERENCES "hello_company" ("id") DEFERRABLE INITIALLY DEFERRED
);
Operações com Modelos
A model Product
está associada a Company
por meio do campo company_id
, que é criado automaticamente no banco de dados. No entanto, no Django, a relação pode ser acessada diretamente pelo campo company da model Product
:
# Obtendo o ID da empresa associada ao produto
Product.objects.get(id=1).company.id
# Obtendo o nome da empresa associada ao produto
Product.objects.get(id=1).company.name
# Obtendo todos os produtos pertencentes a uma empresa específica
Product.objects.filter(company__name="Apple")
A sintaxe modelo__campo
(com dois sublinhados) permite filtrar registros da entidade dependente com base em atributos da entidade principal.
Do ponto de vista da model Company
, não há um campo explícito que a relacione a Product
. No entanto, o Django cria automaticamente um related manager, que permite acessar os produtos associados por meio da sintaxe:
empresa.produto_set
Por padrão, o Django adiciona _set
ao nome da model dependente para criar esse acesso.
Exemplo de uso:
from .models import Company, Product
apple = Company.objects.get(name="Apple")
# Obtendo todos os produtos da empresa
apple.product_set.all()
# Obtendo a quantidade de produtos da empresa
apple.product_set.count()
# Obtendo produtos cujo nome começa com "iPhone"
apple.product_set.filter(name__startswith="iPhone")
O related manager _set
também permite adicionar, modificar e remover objetos da entidade dependente diretamente a partir da entidade principal.
# Criando uma empresa
apple = Company.objects.create(name="Apple")
# Criando um produto associado a essa empresa
apple.product_set.create(name="iPhone 16", price=6789)
# Criando um produto separadamente e depois associando-o à empresa
ipad = Product(name="iPad", price=3456)
# Para adicionar um produto já existente, bulk=False deve ser especificado
apple.product_set.add(ipad, bulk=False)
# Remove todos os produtos da empresa, mas mantém os produtos no banco
# Isso só funciona se o campo ForeignKey permitir valores NULL
# apple.product_set.clear()
# Remove apenas um produto específico da empresa
# ipad = Product.objects.get(name="iPad")
# apple.product_set.remove(ipad)
Três métodos importantes no related manager _set
:
add()
: cria um vínculo entre um objeto dependente e um objeto principal. Na prática, isso corresponde a uma operaçãoUPDATE
no banco para definir a chave estrangeira. Se o objeto dependente ainda não existir no banco,bulk=False
pode ser passado para garantir que ele seja salvo corretamente antes da vinculação.clear()
: remove a relação entre todos os objetos dependentes e a entidade principal. Os objetos continuam existindo no banco, mas a chave estrangeira é definida comoNULL
. Isso só funciona seForeignKey(null=True)
for permitido na model dependente.remove()
: remove a relação entre um único objeto dependente e a entidade principal, sem excluir os registros do banco. Assim comoclear()
, funciona apenas se o campoForeignKey
permitirNULL
.
Documentação oficial: