Resumo : neste tutorial, você aprenderá como ManyToManyField
modelar um relacionamento muitos-para-muitos no Django.
Introdução ao relacionamento muitos-para-muitos do Django
Em um relacionamento muitos para muitos, diversas linhas de uma tabela estão associadas a diversas linhas de outra tabela.
Por exemplo, um funcionário pode ter vários programas de remuneração e um programa de remuneração pode pertencer a vários funcionários.
Portanto, diversas linhas na tabela de funcionários estão associadas a diversas linhas na tabela de remuneração. Conseqüentemente, a relação entre funcionários e programas de remuneração é uma relação muitos-para-muitos.
Normalmente, os bancos de dados relacionais não implementam um relacionamento direto muitos-para-muitos entre duas tabelas. Em vez disso, utiliza uma terceira tabela, a tabela de junção, para estabelecer dois relacionamentos um-para-muitos entre as duas tabelas e a tabela de junção.
O diagrama a seguir ilustra os relacionamentos muitos-para-muitos no banco de dados entre as tabelas hr_employee e hr_compensation:
A hr_employee_compensations
tabela é uma tabela de junção. Possui duas chaves estrangeiras employee_id
e compensation_id
.
A employee_id
chave estrangeira faz referência à id
tabela hr_employee
e a compensation_id
chave estrangeira faz referência id
à hr_compensation
tabela.
Normalmente, você não precisa da id
coluna da hr_employee_compensations
tabela como chave primária e usa ambos employee_id
e compensation_id
como chave primária composta. No entanto, o Django sempre cria a id
coluna como chave primária para a tabela de junção.
Além disso, o Django cria uma restrição única que inclui as colunas employee_id
e compensation_id
. Em outras palavras, não haverá pares duplicados de valores employee_id
e compensation_id
na hr_employee_compensations
tabela.
Para criar um relacionamento muitos-para-muitos no Django, você usa o arquivo ManyToManyField
. Por exemplo, o seguinte usa ManyToManyField
para criar um relacionamento muitos-para-muitos entre modelos Employee
e :Compensation
# ...
class Compensation(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Employee(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
contact = models.OneToOneField(
Contact,
on_delete=models.CASCADE,
null=True
)
department = models.ForeignKey(
Department,
on_delete=models.CASCADE
)
compensations = models.ManyToManyField(Compensation)
def __str__(self):
return f'{self.first_name} {self.last_name}'
Linguagem de código: Python ( python )
Como funciona.
Primeiro, defina uma nova Compensation
classe de modelo que estenda a models.Model
classe.
Segundo, adicione o compensations
campo à Employee
classe. O compensations
campo usa the ManyToManyField
para estabelecer o relacionamento muitos-para-muitos entre as classes Employee
e Compensation
.
Para propagar as alterações dos modelos para o banco de dados, execute o makemigrations
comando:
python manage.py makemigrations
Linguagem de código: CSS ( css )
A saída será algo assim:
Migrations for 'hr':
hr\migrations\0004_compensation_employee_compensations.py
- Create model Compensation
- Add field compensations to employee
Linguagem de código: texto simples ( texto simples )
E execute o migrate
comando:
python manage.py migrate
Linguagem de código: texto simples ( texto simples )
Saída:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, hr, sessions
Running migrations:
Applying hr.0004_compensation_employee_compensations... OK
Linguagem de código: texto simples ( texto simples )
Django criou duas novas tabelas hr_compensation
e uma tabela de junção hr_employee_compensations
como segue:
Criando dados
Primeiro, execute o shell_plus
comando:
python manage.py shell_plus
Linguagem de código: CSS ( css )
Em segundo lugar, crie três programas de remuneração, incluindo Stock
, Bonuses
e Profit Sharing
:
>>> c1 = Compensation(name='Stock')
>>> c1.save()
>>> c2 = Compensation(name='Bonuses')
>>> c2.save()
>>> c3 = Compensation(name='Profit Sharing')
>>> c3.save()
>>> Compensation.objects.all()
<QuerySet [<Compensation: Stock>, <Compensation: Bonuses>, <Compensation: Profit Sharing>]>
Linguagem de código: Python ( python )
Terceiro, obtenha o nome John
e o sobrenome do funcionário Doe
:
>>> e = Employee.objects.filter(first_name='John',last_name='Doe').first()
>>> e
<Employee: John Doe>
Linguagem de código: Python ( python )
Adicionando compensações aos funcionários
Primeiramente, inscreva-se John Doe
nos programas de remuneração stock
( c1
) e bonuses
( c2
) utilizando o add()
método do compensations
atributo e o save()
método do Employee
objeto:
>>> e.compensations.add(c1)
>>> e.compensations.add(c2)
>>> e.save()
Linguagem de código: Python ( python )
Em segundo lugar, acesse todos compensations
os programas John Doe
usando o all()
método do compensations
atributo:
>>> e.compensations.all()
<QuerySet [<Compensation: Stock>, <Compensation: Bonuses>]>
Linguagem de código: Python ( python )
Conforme mostrado claramente no resultado, John Doe
possui dois programas de remuneração.
Terceiro, inscreva-se Jane Doe
em três programas de remuneração, incluindo ações, bônus e participação nos lucros:
>>> e = Employee.objects.filter(first_name='Jane',last_name='Doe').first()
>>> e
<Employee: Jane Doe>
>>> e.compensations.add(c1)
>>> e.compensations.add(c2)
>>> e.compensations.add(c3)
>>> e.save()
>>> e.compensations.all()
<QuerySet [<Compensation: Stock>, <Compensation: Bonuses>, <Compensation: Profit Sharing>]>
Linguagem de código: Python ( python )
Internamente, o Django inseriu os ids dos funcionários e remunerações na tabela de junção:
id | employee_id | compensation_id
----+-------------+-----------------
1 | 5 | 1
2 | 5 | 2
3 | 6 | 1
4 | 6 | 2
5 | 6 | 3
(5 rows)
Linguagem de código: texto simples ( texto simples )
Quarto, encontre todos os funcionários que estavam inscritos no plano de remuneração em ações utilizando o employee_set
atributo do Compensation
objeto:
>>> c1
<Compensation: Stock>
>>> c1.employee_set.all()
<QuerySet [<Employee: John Doe>, <Employee: Jane Doe>]>
Linguagem de código: Python ( python )
Devolveu dois funcionários conforme esperado.
Quinto, você pode usar o employee_set
atributo para encontrar todos os funcionários que possuem o programa de remuneração de participação nos lucros:
>>> c3
<Compensation: Profit Sharing>
>>> c3.employee_set.all()
<QuerySet [<Employee: Jane Doe>]>
Linguagem de código: Python ( python )
Devolveu um funcionário.
Django permite que você faça consultas em todo o relacionamento. Por exemplo, você pode encontrar todos os funcionários que possuem remuneração com id 1:
>>> Employee.objects.filter(compensations__id=1)
<QuerySet [<Employee: John Doe>, <Employee: Jane Doe>]>
Linguagem de código: Python ( python )
Ou com o nome "Profit Sharing"
:
>>> Employee.objects.filter(compensations__name="Profit Sharing")
<QuerySet [<Employee: Jane Doe>]>
Linguagem de código: Python ( python )
Remoção de remunerações dos funcionários
Para remover um programa de remuneração de um funcionário, use o remove()
método do compensations
atributo do Employee
objeto. Por exemplo:
Primeiro, pegue o funcionário cujo nome é Jane Doe
:
>>> e = Employee.objects.filter(first_name='Jane',last_name='Doe').first()
>>> e
<Employee: Jane Doe>
Linguagem de código: Python ( python )
Segundo, remova a profit sharing
compensação ( c3
) Jane Doe
e salve as alterações no banco de dados:
>>> e.compensations.remove(c3)
>>> e.save()
Linguagem de código: Python ( python )
Terceiro, obtenha todos os programas de compensação de Jane Doe
:
>>> e.compensations.all()
<QuerySet [<Compensation: Stock>, <Compensation: Bonuses>]>
Linguagem de código: Python ( python )
Agora, Jane Doe
restam dois programas de remuneração.
Baixe o código-fonte do relacionamento muitos-para-muitos do Django .
Resumo
- Em um relacionamento muitos para muitos, diversas linhas de uma tabela estão associadas a diversas linhas de outra tabela.
- Os bancos de dados relacionais usam uma tabela de junção para estabelecer um relacionamento muitos-para-muitos entre duas tabelas.
- Use
ManyToManyField
para modelar um relacionamento muitos-para-muitos entre modelos no Django.