Relacionamento muitos-para-muitos do Django

Resumo : neste tutorial, você aprenderá como ManyToManyFieldmodelar 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_compensationstabela é uma tabela de junção. Possui duas chaves estrangeiras employee_id e compensation_id.

A employee_idchave estrangeira faz referência à idtabela hr_employeee a compensation_idchave estrangeira faz referência idà hr_compensationtabela.

Normalmente, você não precisa da idcoluna da hr_employee_compensationstabela como chave primária e usa ambos employee_ide compensation_idcomo chave primária composta. No entanto, o Django sempre cria a idcoluna 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_ide compensation_id. Em outras palavras, não haverá pares duplicados de valores employee_ide compensation_idna hr_employee_compensationstabela.

Para criar um relacionamento muitos-para-muitos no Django, você usa o arquivo ManyToManyField. Por exemplo, o seguinte usa ManyToManyFieldpara criar um relacionamento muitos-para-muitos entre modelos Employeee :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 Compensationclasse de modelo que estenda a models.Modelclasse.

Segundo, adicione o compensationscampo à Employeeclasse. O compensationscampo usa the ManyToManyFieldpara estabelecer o relacionamento muitos-para-muitos entre as classes Employeee Compensation.

Para propagar as alterações dos modelos para o banco de dados, execute o makemigrationscomando:

python manage.py makemigrationsLinguagem 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 employeeLinguagem de código:  texto simples  ( texto simples )

E execute o migratecomando:

python manage.py migrateLinguagem 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_compensatione uma tabela de junção hr_employee_compensationscomo segue:

Criando dados

Primeiro, execute o shell_pluscomando:

python manage.py shell_plusLinguagem de código:  CSS  ( css )

Em segundo lugar, crie três programas de remuneração, incluindo Stock, Bonusese 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 Johne 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 Doenos programas de remuneração stock( c1) e bonuses ( c2) utilizando o add()método do compensationsatributo e o save()método do Employeeobjeto:

>>> e.compensations.add(c1)
>>> e.compensations.add(c2) 
>>> e.save()Linguagem de código:  Python  ( python )

Em segundo lugar, acesse todos compensationsos programas John Doeusando o all()método do compensationsatributo:

>>> e.compensations.all()
<QuerySet [<Compensation: Stock>, <Compensation: Bonuses>]>Linguagem de código:  Python  ( python )

Conforme mostrado claramente no resultado, John Doepossui dois programas de remuneração.

Terceiro, inscreva-se Jane Doeem 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_setatributo do Compensationobjeto:

>>> 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_setatributo 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 compensationsatributo do Employeeobjeto. 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 sharingcompensação ( c3) Jane Doee 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 Doerestam 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 ManyToManyFieldpara modelar um relacionamento muitos-para-muitos entre modelos no Django.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *