Ответ
В Django Manager — это интерфейс, через который модели Django выполняют операции с базой данных. Каждая модель имеет как минимум один менеджер, по умолчанию он называется objects.
Основная задача менеджера — предоставлять методы для получения объектов из базы данных. Результатом работы таких методов обычно является QuerySet.
Зачем нужны кастомные менеджеры?
Пользовательские менеджеры создают для двух основных целей:
- Добавление новых методов: Для инкапсуляции часто используемых запросов на уровне модели.
- Изменение стандартного
QuerySet: Для постоянной фильтрации объектов, возвращаемых менеджером.
Пример кастомного менеджера
Допустим, у нас есть модель Post и мы часто хотим получать только опубликованные посты.
from django.db import models
from django.utils import timezone
# 1. Создаем кастомный менеджер
class PublishedManager(models.Manager):
def get_queryset(self):
# Переопределяем базовый QuerySet, чтобы он всегда фильтровал по статусу и дате
return super().get_queryset().filter(
status='published',
publish__lte=timezone.now()
)
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=250)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
publish = models.DateTimeField(default=timezone.now)
# 2. Подключаем менеджеры к модели
objects = models.Manager() # Стандартный менеджер
published = PublishedManager() # Наш кастомный менеджер
def __str__(self):
return self.title
Использование
Теперь вместо сложных фильтров в коде можно использовать наш новый менеджер:
# Получить ВСЕ посты, включая черновики
all_posts = Post.objects.all()
# Получить ТОЛЬКО опубликованные посты
# Это короче, чище и менее подвержено ошибкам, чем Post.objects.filter(status='published', ...)
published_posts = Post.published.all() Ответ 18+ 🔞
А, менеджеры в Джанго! Ну, это же, блядь, как главный завхоз на складе ваших моделей, понимаешь? По умолчанию у каждой модели сидит такой дедок по имени objects, который всё знает, где что лежит, и может тебе любую коробку из базы данных принести.
Но иногда этот дедок — старый, блядь, пердунок, и ему надо либо новые фокусы показать, либо он тебе постоянно суёт в руки не то, что надо. Вот тут и начинается магия кастомных менеджеров.
Зачем они, эти самопальные завхозы?
А вот, блядь, зачем:
- Новые трюки в рукав запихнуть. Чтобы не писать один и тот же ебучий фильтр в каждом втором view, можно научить менеджера делать это за тебя. Инкапсуляция, мать её!
- Постоянно фильтровать, как параноик. Чтобы менеджер по умолчанию возвращал только то, что нужно, а не всю хуйню подряд. Например, только опубликованные статьи, а не черновики, которые ты в пьяном угаре накодил в три ночи.
Смотри сюда, как это выглядит вживую
Допустим, у нас модель Post (пост, статья, хуита — называй как хочешь). И нам постоянно надо тащить из базы только те, что уже опубликованы. Делать это руками — терпения ноль, ебать. Вот как делают умные люди:
from django.db import models
from django.utils import timezone
# 1. Рожаем своего менеджера. Назовём его PublishedManager, чтоб всё по-взрослому.
class PublishedManager(models.Manager):
def get_queryset(self):
# Берем стандартную корзину с объектами (QuerySet) и насильно, блядь, фильтруем.
# Только 'published' и только те, у кого дата публикации уже наступила.
return super().get_queryset().filter(
status='published',
publish__lte=timezone.now()
)
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Черновик (пока никому не показывай, стыдно)'),
('published', 'Опубликовано (ура, товарищи!)'),
)
title = models.CharField(max_length=250)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
publish = models.DateTimeField(default=timezone.now)
# 2. Подключаем менеджеров к модели. Важно не перепутать!
objects = models.Manager() # Стандартный дедок. Видит ВСЁ, даже черновики.
published = PublishedManager() # Наш параноик. Видит ТОЛЬКО опубликованное.
def __str__(self):
return self.title
И как теперь этим пользоваться, спросишь ты?
Да элементарно, Ватсон! Смотри:
# Запросим у старого дедка objects ВСЕ посты. Он притащит и черновики тоже.
all_posts = Post.objects.all() # Может вернуть какую-нибудь дичь вроде "Мой первый пост про котят (черновик)".
# А теперь спросим у нашего параноика published. Он строгий, блядь.
published_posts = Post.published.all() # Вернёт только то, что прошло цензуру и готово к показу.
Вот и вся магия. Вместо того чтобы каждый раз писать Post.objects.filter(status='published', publish__lte=timezone.now()) и рисковать ошибиться, ты просто пишешь Post.published.all(). Красота, ёпта! Чисто, понятно, и в коде не надо искать, где ты опять забыл добавить фильтр по дате.