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')
Вернуться на верх