Resumo : neste tutorial, você aprenderá como adicionar campos extras usando ManyToManyField
o argumento through.
Em um relacionamento muitos para muitos , várias linhas de uma tabela estão associadas a várias linhas de outra tabela. Para estabelecer um relacionamento muitos para muitos, os bancos de dados relacionais usam uma terceira tabela chamada tabela de junção e criam dois relacionamentos um para muitos a partir das tabelas de origem.
Normalmente, a tabela de junção contém os valores de id das tabelas de origem para que as linhas de uma tabela possam estar relacionadas às linhas da outra tabela.
Às vezes, você pode querer adicionar campos extras à tabela de junção. Por exemplo, cada funcionário pode ter vários empregos durante sua carreira.
Para rastrear quando um funcionário aceita um emprego, você pode adicionar os campos begin_date
e end_date
à tabela de junção.
Para fazer isso no Django, você usa o ManyToManyField
com o through
argumento.
Por exemplo, o seguinte mostra como associar um funcionário a vários cargos por meio de atribuições:
class Employee(models.Model):
# ...
class Job(models.Model):
title = models.CharField(max_length=255)
employees = models.ManyToManyField(Employee, through='Assignment')
def __str__(self):
return self.title
class Assignment(models.Model):
employee = models.ForeignKey(Employee, on_delete=models.CASCADE)
position = models.ForeignKey(Job, on_delete=models.CASCADE)
begin_date = models.DateField()
end_date = models.DateField(default=date(9999, 12, 31))
Linguagem de código: Python ( python )
Como funciona.
- Primeiro, defina o
Job
modelo, adicione oemployees
atributo que usaManyToManyField
e passeAssignment
comothrough
argumento. - Segundo, defina a
Assignment
classe que possui duas chaves estrangeiras, uma vinculada aoEmployee
modelo e a outra vinculada aoJob
modelo. Além disso, adicione os atributosbegin_date
eend_date
aoAssignment
modelo.
Execute o makemigrations
para fazer novas migrações:
python manage.py makemigrations
Linguagem de código: Python ( python )
Saída:
Migrations for 'hr':
hr\migrations\0005_assignment_job_assignment_job.py
- Create model Assignment
- Create model Job
- Add field job to assignment
Linguagem de código: Python ( python )
E execute o migrate
comando para aplicar as alterações ao banco de dados:
python manage.py migrate
Linguagem de código: Python ( python )
Saída:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, hr, sessions
Running migrations:
Applying hr.0005_assignment_job_assignment_job... OK
Linguagem de código: Python ( python )
Nos bastidores, o Django cria as tabelas hr_job
e hr_assignment
no banco de dados:
Esta hr_assignment
é a tabela de junção. Além dos campos employee_id
e position_id
, possui os campos begin_date
e end_date
.
Criando novos empregos
Primeiro, execute o shell_plus
comando:
python manage.py shell_plus
Linguagem de código: Python ( python )
Em segundo lugar, crie três novos cargos:
>>> j1 = Job(title='Software Engineer I')
>>> j1.save()
>>> j2 = Job(title='Software Engineer II')
>>> j2.save()
>>> j3 = Job(title='Software Engineer III')
>>> j3.save()
>>> Job.objects.all()
<QuerySet [<Job: Software Engineer I>, <Job: Software Engineer II>, <Job: Software Engineer III>]>
Linguagem de código: Python ( python )
Criando instâncias para os modelos intermediários
Primeiro, encontre o funcionário com o nome John Doe
e Jane Doe
:
>>> e1 = Employee.objects.filter(first_name='John',last_name='Doe').first()
>>> e1
<Employee: John Doe>
>>> e2 = Employee.objects.filter(first_name='Jane', last_name='Doe').first()
>>> e2
<Employee: Jane Doe>
Linguagem de código: Python ( python )
Segundo, crie instâncias do modelo intermediário ( Assignment
):
>>> from datetime import date
>>> a1 = Assignment(employee=e1,job=j1, begin_date=date(2019,1,1), end_date=date(2021,12,31))
>>> a1.save()
>>> a2 = Assignment(employee=e1,job=j2, begin_date=date(2022,1,1))
>>> a2.save()
>>> a3 = Assignment(employee=e2, job=j1, begin_date=date(2019, 3, 1))
>>> a3.save()
Linguagem de código: Python ( python )
Terceiro, encontre os funcionários que ocupam o Software Engineer I
cargo ( p1
):
>>> j1.employees.all()
<QuerySet [<Employee: John Doe>, <Employee: Jane Doe>]>
Linguagem de código: Python ( python )
Nos bastidores, o Django executa a seguinte consulta:
SELECT
"hr_employee"."id",
"hr_employee"."first_name",
"hr_employee"."last_name",
"hr_employee"."contact_id",
"hr_employee"."department_id"
FROM "hr_employee"
INNER JOIN "hr_assignment"
ON ("hr_employee"."id" = "hr_assignment"."employee_id")
WHERE "hr_assignment"."job_id" = 1
Linguagem de código: Python ( python )
Da mesma forma, você pode encontrar todos os funcionários que ocupam o Software Engineer II
cargo:
>>> j2.employees.all()
<QuerySet [<Employee: John Doe>]>
Linguagem de código: Python ( python )
Removendo instâncias das instâncias do modelo intermediário
Primeiro, remova Jane Doe
( e2
) do Software Engineer II
trabalho usando o remove()
método:
>>> j2.employees.remove(e2)
Linguagem de código: Python ( python )
Segundo, remova todos os funcionários do Software Engineer I
trabalho usando o clear()
método:
>>> j1.employees.clear()
Linguagem de código: Python ( python )
O j1
trabalho não deve ter nenhum funcionário agora:
>>> j1.employees.all()
<QuerySet []>
Linguagem de código: CSS ( css )
Resumo
- Use o
through
argumento paraManyToManyField
adicionar campos extras ao relacionamento muitos para muitos.