Atualizado: 18/01/2024

Relacionamento Um-para-Um (One-to-One) no Django

O relacionamento Um-para-Um ocorre quando um registro de uma entidade pode estar associado a, no máximo, um registro de outra entidade. No Django, esse tipo de relação é representado pelo campo OneToOneField.

Um exemplo prático seria separar os dados de um usuário entre duas models:

  • A model User armazena informações básicas, como nome.

  • A model Account armazena dados de autenticação, como login e senha.

from django.db import models  

class User(models.Model):  
    name = models.CharField(max_length=20)  

class Account(models.Model):  
    login = models.CharField(max_length=20)  
    password = models.CharField(max_length=20)  
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)

O campo OneToOneField estabelece a relação um-para-um entre Account e User. O primeiro argumento especifica a model associada, que neste caso é User. O parâmetro on_delete=models.CASCADE garante que, ao remover um usuário, o registro correspondente em Account também seja excluído. Além disso, primary_key=True transforma o campo user na chave primária da model Account, eliminando a necessidade de um campo id separado.

Após a migração, um banco SQLite criaria as seguintes tabelas:

CREATE TABLE "hello_user" (
    "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
    "name" varchar(20) NOT NULL
);

CREATE TABLE "hello_account" (
    "login" varchar(20) NOT NULL, 
    "password" varchar(20) NOT NULL, 
    "user_id" bigint NOT NULL PRIMARY KEY REFERENCES "hello_user" ("id") DEFERRABLE INITIALLY DEFERRED
);

O campo user_id na tabela hello_account atua como chave primária e estrangeira ao mesmo tempo, garantindo que cada Account esteja vinculada a um único User.

Operações com Models

A model Account possui um campo user, permitindo acessar e modificar o usuário associado.

# Criando um usuário  
sam = User.objects.create(name="Sam")  

# Criando uma conta para o usuário  
acc = Account.objects.create(login="1234", password="6565", user=sam)  

# Atualizando o nome do usuário  
acc.user.name = "Bob"  
acc.user.save()  

print(f"{acc.user.name}, login: {acc.login}, password: {acc.password}")  
# Saída: Bob, login: 1234, password: 6565  

A partir da model Account, é possível acessar diretamente o usuário associado e modificar seus dados.

Mesmo que a model User não tenha um campo explícito apontando para Account, o Django cria automaticamente um related manager, permitindo acessar a conta associada pelo nome da model dependente (account, neste caso):

# Criando um usuário  
tom = User.objects.create(name="Tom")  

# Criando uma conta e associando-a ao usuário  
acc = Account(login="1234", password="6565")  
tom.account = acc  
tom.account.save()  

# Atualizando os dados da conta  
tom.account.login = "qwerty"  
tom.account.password = "123456"  
tom.account.save()  

print(f"{tom.name}, login: {tom.account.login}, password: {tom.account.password}")  
# Saída: Tom, login: qwerty, password: 123456  

O Django cria automaticamente o atributo account na model User, permitindo acessar diretamente os dados da model Account.

Filtro de Dados

A relação um-para-um permite realizar consultas baseadas nos atributos das duas models:

# Obtendo um usuário  
tom = User.objects.get(name="Tom")  

# Obtendo a conta associada ao usuário  
tom_acc = Account.objects.get(user=tom)  
print(f"login: {tom_acc.login}, password: {tom_acc.password}")  
# Saída: login: qwerty, password: 123456  

# Obtendo uma conta pelo nome do usuário  
bob_acc = Account.objects.get(user__name="Bob")  
print(f"login: {bob_acc.login}, password: {bob_acc.password}")  

# Obtendo um usuário a partir do login da conta  
user = User.objects.get(account__login="qwerty")  
print(user.name)  

A sintaxe campo__atributo (com dois sublinhados) permite acessar atributos de models relacionadas no filtro.

Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com