Пользовательский менеджер моделей Django
Вы можете использовать собственный менеджер моделей в Django в конкретной модели, расширив класс Manager и создав экземпляр своего собственного менеджера в своей модели.
Есть две причины, которые могут расширить класс Manager: добавить дополнительный метод менеджера или изменить исходный QuerySet, возвращаемый менеджером.
Добавление дополнительного метода менеджера
Здесь я собираюсь добавить пользовательский метод менеджера, который отвечает за получение всех сотрудников возрастом старше 30 лет из таблицы Employee. Чтобы добавить дополнительный метод менеджера, мы должны расширить класс и определить метод внутри того класса, который мы хотим создать models.Manager
Добавление дополнительных методов диспетчера является предпочтительным способом реализации способа добавления функциональности метки таблицы.
Этот пользовательский менеджер добавляет метод get_age().
class CustomManager(models.Manager):
def get_age(self):
return self.filter(age__gt=30)
class Employee(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
age = models.SmallIntegerField(null=True)
created = models.DateTimeField(default=timezone.now)
work_experience = models.SmallIntegerField(default=0)
contact = models.OneToOneField(Contact, on_delete=models.CASCADE, null=True)
department = models.ForeignKey(Department, on_delete=models.CASCADE, default=None)
compensations = models.ManyToManyField(Compensation)
persons = CustomManager()
def __str__(self):
return f'{self.first_name} {self.last_name}'
Таким образом, мы успешно добавили пользовательский менеджер моделей CustomManager вместе с методом get_age(). Теперь вы можете получить всех сотрудников, старше 30 лет, используя Employee.persons.get_age() оператор.
Давайте разберемся, что такое начальный QuerySet, для использования модели Employee, когда вы используете Employee.objects.all()оператор, он возвращает QuerySet (экземпляры моделей Employee), и этот QuerySet называется начальным QuerySet.
Базовый запрос менеджера по умолчанию возвращает все объекты модели, но мы можем это изменить. Метод get_queryset() вернет QuerySet вместе с требуемыми свойствами. Давайте сделаем так, чтобы при обращении к Employee.persons.all() мы выводили список сотрудников, которые относятся к департаменту = 1, в нашем случае этот департамент называется "IT"
class CustomManager(models.Manager):
def get_age(self):
return self.filter(age__gt=30)
def get_queryset(self):
return super().get_queryset().filter(department=1)
class Employee(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
age = models.SmallIntegerField(null=True)
created = models.DateTimeField(default=timezone.now)
work_experience = models.SmallIntegerField(default=0)
contact = models.OneToOneField(Contact, on_delete=models.CASCADE, null=True)
department = models.ForeignKey(Department, on_delete=models.CASCADE, default=None)
compensations = models.ManyToManyField(Compensation)
objects = models.Manager()
persons = CustomManager()
def __str__(self):
return f'{self.first_name} {self.last_name}'
В приведенной выше модели Django есть два менеджера: persons возвращает всех сотрудников, исходя из их фильтрации по департаменту, а objects возвращает все экземпляры сотрудников.
Пользовательский метод QuerySet
Здесь вы должны помнить один самый важный момент: метод Employee.objects.all() возвращает QuerySet, который является экземпляром класса QuerySet.
Класс QuerySet, написанный внутри пакета django.db.models.
До сих пор мы видели, как добавить дополнительный метод менеджера и изменить QuerySet исходного менеджера. Теперь я собираюсь добавить несколько дополнительных методов QuerySet, которые будут напрямую доступны из менеджера модели в Django, а также применяться к QuerySet.
Для этого примера я добавлю два метода: get_experience() для получения только опытных сотрудников и get_not_experienced() для получения только сотрудников с низким опытом.
class EmployeeQuerySet(models.QuerySet):
def get_experience(self):
return self.filter(work_experience__gt=3)
def get_not_experienced(self):
return self.filter(work_experience__lt=3)
class CustomManager(models.Manager):
def get_queryset(self):
return EmployeeQuerySet(self.model, using=self._db)
def get_experience(self):
return self.get_queryset().get_experience()
def get_not_experienced(self):
return self.get_queryset().get_not_experienced()
class Employee(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
age = models.SmallIntegerField(null=True)
created = models.DateTimeField(default=timezone.now)
work_experience = models.SmallIntegerField(default=0)
contact = models.OneToOneField(Contact, on_delete=models.CASCADE, null=True)
department = models.ForeignKey(Department, on_delete=models.CASCADE, default=None)
compensations = models.ManyToManyField(Compensation)
persons = CustomManager()
def __str__(self):
return f'{self.first_name} {self.last_name}'
Этот пример позволяет вам вызывать и get_experience() и get_not_experienced() непосредственно из менеджера Employee.persons c пользовательским QuerySet.
Пользовательские менеджеры и наследование моделей
Вот как Django обрабатывает пользовательские менеджеры и наследование моделей :
- Менеджеры из базовых классов всегда наследуются дочерним классом, используя обычный порядок разрешения имен Python (имена в дочернем классе переопределяют все остальные; затем идут имена в первом родительском классе и так далее).
- Если для модели и/или ее родителей не объявлены менеджеры, Django автоматически создает
objectsменеджер. - Менеджер по умолчанию для класса — это либо тот, который выбран с помощью
Meta.default_manager_name, либо первый менеджер, объявленный в модели, либо менеджер по умолчанию первой родительской модели.