Создание данных
Сначала выполните shell_plus команду:
python manage.py shell_plus
Создадим три зарплатные программы: Stock, Bonusesи Profit Sharing:
c1 = Compensation(name='Stock')
c1.save()
c2 = Compensation(name='Bonuses')
c2.save()
c3 = Compensation(name='Profit Sharing')
c3.save()
Давайте получим сотрудника с именем John и фамилией Doe:
e = Employee.objects.filter(first_name='John',last_name='Doe').first()
Добавление оплаты сотрудникам
Сначала зарегистрируйтесь John Doe в компенсационных программах stock (c1) и bonuses (c2), используя add() метод атрибута compensations и save() метод объекта Employee:
e.compensations.add(c1)
e.compensations.add(c2)
e.save()
Во-вторых, получить доступ ко всей compensations программе с John Doe использованием all() метода атрибута compensations:
e.compensations.all()
Как ясно показано на рисунке, John Doe имеет две программы компенсации.
Теперь давайте добавим второму сотруднику Jane Doe в три зарплатные программы, включая оклад, бонусы и участие в прибыли компании:
e = Employee.objects.filter(first_name='Jane',last_name='Doe').first()
e.compensations.add(c1)
e.compensations.add(c2)
e.compensations.add(c3)
e.save()
Внутри Django вставил идентификаторы сотрудников и компенсаций в таблицу соединений - hr_employee_compensations:
Давайте найдем всех сотрудников, которые были зачислены в план компенсации акций, используя employee_set атрибут объекта Compensation:
c1
c1.employee_set.all()
Как и ожидалось, он вернул двух сотрудников.
Вы можете использовать employee_set атрибут, чтобы найти всех сотрудников, у которых есть программа вознаграждения с участием в прибылях:
c3
c3.employee_set.all()
Вернулся один сотрудник. Django позволяет вам запрашивать отношения. Например, вы можете найти всех сотрудников, у которых есть компенсация с идентификатором 1:
Employee.objects.filter(compensations__id=1)
Или с именем "Profit Sharing":
Employee.objects.filter(compensations__name="Profit Sharing")
Снятие связи зарплат с сотрудников
Для снятия зарплатной программы с работника используется remove() метод атрибута compensations объекта Employee. Например:
Сначала найдите сотрудника, имя которого Jane Doe:
e = Employee.objects.filter(first_name='Jane',last_name='Doe').first()
e.compensations.remove(c3)
e.save()
В-третьих, получите все зарплатные программы Jane Doe:
e.compensations.all()
Теперь Jane Doeосталось две зарплатные программы.
Конструктор класса ManyТoManyField поддерживает дополнительные необязательные параметры limit_choices_to, related_name, related_query_name и db_constraint, описанные в предыдущем разделе , а также следующие:
- synunetrical - используется только в тех случаях, когда модель связывается сама с собой. Если
True, Django создаст симметричную связь, действующую в обоих направлениях. ЕслиFalse, то связь будет асимметричной. Значение по умолчанию -True. Для асимметричной связи Django создаст в классе модели атрибут для доступа к записям связанной модели в обратном направлении. - through - класс модели, которая представляет связующую таблицу (связующая модель) либо в виде ссылки, либо в виде имени, представленном строкой. Если класс не указан, то связующая таблица будет создана самим Django. При использовании связующей модели нужно иметь в виду следующее:
- поле внешнего ключа для связи объявляется и в ведущей, и в ведомой моделях. При создании этих полей следует указать как саму связующую модель (параметр
through), так и поля внешних ключей, по которым будет установлена связь (параметрthrough_fields, описанный далее); - в связующей модели следует явно объявить поля внешних ключей для установления связи с обеими связываемыми моделями: и ведущей, и ведомой;
Например если мы используем модель:
from django.db import models class Student(models.Model): name = models.CharField(max_length=200) class Course(models.Model): name = models.CharField(max_length=200) students = models.ManyToManyField(Student, through="Register") class Register(models.Model): student = models.ForeignKey(Student, on_delete=models.CASCADE) course = models.ForeignKey(Course, on_delete=models.CASCADE) date = models.DateField()То через данный параметр мы можем вручную указать промежуточную таблицу для управления отношениями "многие ко многим". В результате схема нашей БД будет выглядеть следующим образом.
- поле внешнего ключа для связи объявляется и в ведущей, и в ведомой моделях. При создании этих полей следует указать как саму связующую модель (параметр
- through_fields - используется, если связь устанавливается через связующую модель, записанную в параметре
throughконструктора. Указывает поля внешних ключей, по которым будет создаваться связь. Значение параметра должно представлять собой кортеж из двух элементов: имени поля ведущей модели и имени поля ведомой модели, записанных в виде строк. Если параметр не указан, то поля будут созданы самим фреймворком. Например если мы используем модель:from django.db import models class Student(models.Model): name = models.CharField(max_length=200) class Course(models.Model): name = models.CharField(max_length=200) students = models.ManyToManyField(Student, through="Register", through_fields=('course', 'student')) class Register(models.Model): student = models.ForeignKey(Student, related_name="student", on_delete=models.CASCADE) intern = models.ForeignKey(Student, related_name="intern", on_delete=models.CASCADE) course = models.ForeignKey(Course, on_delete=models.CASCADE) date = models.DateField()В приведенном выше примере модель
Registerимеет два внешних ключа Student у полей student и intern, теперь Django не знает, какой из них использовать, и в результате не сможет создать таблицы. В этом случае вы должны явно указать, какие внешние ключи Django должен использовать с помощьюthrough_fields.
- db_tаblе - имя связующей таблицы. Обычно применяется, если связующая модель не используется. Если оно не указано, то связующая таблица получит имя по умолчанию.