Django - менеджер на отношениях ManyToMany
У меня есть 3 модели
class Person(models.Model):
name = models.CharField(max_length=128)
class Company(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField (Person, through = 'Membership', related_name = 'companies')
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
company = models.ForeignKey(Company, on_delete=models.CASCADE)
is_admin = models.BooleanField()
Затем я могу вызвать person.companies.all()
, чтобы получить список компаний, связанных с человеком.
Как мне создать менеджера, чтобы у него был список компаний, связанных с персоной, но чья персона является администратором (is_admin = True)?
Вы можете фильтровать с помощью:
person.companies.filter(membership__is_admin=True)
Это отфильтрует таблицу перекрестков Membership
таким образом, что она будет извлекать только Company
, для которых Membership
имеет is_admin
значение True
.
Другой вариант - получить это с помощью:
Company.objects.filter(membership__is_admin=True, members=person)
Вы можете прикрепить это к модели Person
с помощью:
class Person(models.Model):
name = models.CharField(max_length=128)
@property
def admin_companies(self):
return self.companies.filter(membership__is_admin=True)
Вы можете создать менеджера следующим образом:
managers.py
:
from django.db import models
class AdminCompaniesManager(models.Manager):
def get_queryset(self):
return super().get_queryset().companies.filter(membership__is_admin=True)
и затем в вашей Person
модели (напомните, пожалуйста, менеджеру objects
):
class Person(models.Model):
name = models.CharField(max_length=128)
objects = models.Manager()
administered_companies = AdminCompaniesManager()
Теперь вы можете легко вызвать следующее (например, в ваших представлениях):
my_person.administered_companies.all()
PS: очень эффективным вариантом (например, если вы находитесь в представлении и вам нужен список идентификаторов компаний для данного человека) является прямой запрос к модели членства, таким образом вы можете оптимизировать запрос для получения данных из БД, избегая джойнов:
Membership.objects.filter(is_admin=True, person=person).values_list('company_id')