Введение в отношения «многие-ко-многим» в Django
В отношении «многие-ко-многим» несколько строк в таблице связаны с несколькими строками в другой таблице. Обе модели здесь выступают как равноправные, и определить, какая из них первичная, а какая вторичная, не представляется возможным.
Например, у сотрудника может быть несколько зарплатных программ, и каждая зарплатная программа может принадлежать нескольким сотрудникам.
Если нас есть зарплатные программы: "оклад", "бонусы", "проценты от дохода", то у каждого сотрудника их может быть несколько.
Таким образом, несколько строк в таблице сотрудников связаны с несколькими строками в таблице зарплат. Следовательно, отношения между работниками и компенсационными программами являются отношениями «многие-ко-многим».
Как правило, реляционные базы данных не реализуют прямую связь «многие-ко-многим» между двумя таблицами. Вместо этого они использует третью таблицу, таблицу соединения, для установления двух отношений «один-ко-многим» между двумя таблицами и таблицей соединения.
Следующая диаграмма иллюстрирует отношения «многие-ко-многим» в базе данных между таблицами hr_employee и hr_compensation:
Таблица hr_employee_compensations является соединительной. Она имеет два внешних ключа employee_id и compensation_id.
Внешний employee_id ключ ссылается на id таблицу hr_employee, а compensation_id внешний ключ ссылается id на hr_compensation таблицу.
Как правило, вам не нужен id столбец в hr_employee_compensations таблице в качестве первичного ключа , и вы можете использовать оба employee_id и compensation_id в качестве составного первичного ключа. Однако Django всегда создает id столбец в качестве первичного ключа для таблицы соединения.
Кроме того, Django создает уникальное ограничение , включающее столбцы employee_id и compensation_id. Другими словами, в таблице не будет повторяющихся пар employee_id и compensation_id значений hr_employee_compensations.
Чтобы создать отношения «многие-ко-многим» в Django, вы используете файл ManyToManyField. Доработаем нашу модель, добавив ManyToManyField для создания отношения «многие-ко-многим» между моделями Employee и Compensation:
from django.db import models
class Compensation(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Contact(models.Model):
phone = models.CharField(max_length=50, unique=True)
address = models.CharField(max_length=50)
def __str__(self):
return self.phone
class Department(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(null=True, blank=True)
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, default=None)
compensations = models.ManyToManyField(Compensation)
def __str__(self):
return f'{self.first_name} {self.last_name}'
Поле compensations использует ManyToManyField для установления отношения «многие-ко-многим» между классами Employee и Compensation.
Выполним миграции и посмотрим нашу базу данных:
python manage.py makemigrations
python manage.py migrate
Как мы видим Django создал две новые таблицы hr_compensation и таблицу соединений hr_employee_compensations следующим образом:
В следующем шаге начнем работать с запросами с данным типом отношений.