Менеджеры Django
В инструкции Book.objects.all() objects - это специальный атрибут, посредством которого выполняется запрос к базе данных. В главе 5 мы кратко остановились на нем, назвав менеджером модели. Теперь пришло время более детально изучить, что такое менеджеры и как с ними работать.
В двух словах, менеджер модели - это объект, с помощью которого Django выполняет запросы к базе данных. Каждая модель Django имеет по меньшей мере один менеджер, и вы можете создавать свои менеджеры для организации специализированных видов доступа.
Потребность создания собственного менеджера может быть вызвана двумя причинами: необходимостью добавить менеджеру дополнительные методы и/или необходимостью модифицировать исходный объект QuerySet, возвращаемый менеджером.
Добавление методов в менеджер
Добавление дополнительных методов в менеджер - это рекомендуемый способ включить в модель функциональность на уровне таблицы. Функциональность уровня таблицы доступна не в одном, а сразу в нескольких экземплярах модели. (Для реализации функциональности на уровне строк, то есть функций, применяемых к единственному объекту модели, используются методы модели, которые мы рассмотрим ниже в этой главе.)
В качестве примера, добавим в модель Book метод менеджера title_ count О, принимающий ключевое слово и возвращающий количество книг, в названиях которых встречается это слово. (Пример немного искусственный, но удобный для иллюстрации работы менеджеров.)
# models.ру
from django.db import models
tt . . . Модели Author и Publisher опущены .. .
class BookManager(models.Manager): def title_count(self, keyword):
return self.filter(title____________________ icontains^keyword).count()
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
num_pages = models IntegerField(blank-True, null^True)
objects = BookManager()
def __unicode__(self): return self.title
Имея такой менеджер, мы можем использовать его следующим образом:
»> Book.objects. title_count(‘ django’ ) 4
»> Book.objects. title_count(‘ python’ ) 18
Отметим следующие моменты:
• Мы создали класс BookManager, который расширяет класс django.db. models.Manager. В нем определен единственный метод title_count(), выполняющий вычисление. Обратите внимание на вызов self.f ilter(), где self - ссылка на сам объект менеджера.
• Мы присвоили значение BookManagerQ атрибуту objects модели. Тем самым мы заменили менеджер по умолчанию, который называется objects и создается автоматически, если не задан никакой другой менеджер. Назвав наш менеджер objects, а не как-то иначе, мы сохранили совместимость с автоматически создаваемыми менеджерами.
Зачем может понадобиться добавлять такие методы, как title_count()? Чтобы инкапсулировать часто употребляемые запросы и не дублировать код.
Модификация исходных объектов QuerySet
Стандартный объект QuerySet, возвращаемый менеджером, содержит все объекты, хранящиеся в таблице. Например, Book.objects.allQ возвращает все книги в базе данных.
Стандартный объект QuerySet можно переопределить, заместив метод Manager.get_query_set(). Этот метод должен вернуть объект QuerySet, обладающий нужными вам свойствами.
Например, в следующей модели имеется два менеджера - один возвращает все объекты, а другой только книги Роальда Даля.
from django.db import models
ft Сначала определяем подкласс класса Manager, class DahlManager(models.Manager):
def get_query_set(self):
return super(DahlManager, self).get_query_set().filter( author^’Roald Dahl* )
tt Затем явно присоединяем его к модели Book, class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50) # . . .
objects = models.Manager() tt Менеджер по умолчанию. dahl_objects = DahlManager() tt Специальный менеджер.
В этой модели вызов Book.objects.all() вернет все книги в базе данных, а вызов Book.dahl_objects.all() - только книги, написанные Роальдом Далем. Отметим, что мы явно присвоили атрибуту objects экземпляр стандартного менеджера Manager, потому что в противном случае у нас оказался бы только менеджер dahl_objects.
Разумеется, поскольку get_query_set() возвращает объект QuerySet, к нему можно применять методы filterQ, excludeO и все остальные методы QuerySet. Поэтому каждая из следующих инструкций является допустимой:
Book.dahl_objects.all()
Book.dahl_objects.filter(title=’Matilda’)
Book.dahl_objects.count()
В этом примере демонстрируется еще один интересный прием: использование нескольких менеджеров в одной модели. К любой модели можно присоединить сколько угодно экземпляров класса ManagerQ. Таким способом легко можно определить фильтры, часто применяемые к модели.
Рассмотрим следующий пример.
class MaleManager(models.Manager): def get_query_set(self):
return super(MaleManager, self).get_query_set().filter(sex-‘M’)
class FemaleManager(models.Manager): def get_query_set(self):
return super(FemaleManager, self).get_query_set().filter(sex=’F’)
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
sex = models.CharField(max_length=1, choicest(‘M’, ‘Male’),
(‘F’, ‘Female’)))
people = models.Manager() men = MaleManager() women = FemaleManager()
Теперь можно обращаться к методам Person.men.allQ, Person.women.allQ и Person.people.all() и получать предсказуемые результаты.
Следует отметить, что первый менеджер, определенный в классе модели, имеет особый статус. Django считает его менеджером по умолчанию, и в некоторых частях фреймворка (но не в административном интерфейсе) только этот менеджер и будет использоваться. Поэтому нужно тщательно продумывать, какой менеджер назначать по умалчанию, чтобы вдруг не оказаться в ситуации, когда переопределенный метод get_query_ set() возвращает не те объекты, которые вам нужны.
Источник: Головатый А., Каплан-Мосс Дж. Django. Подробное руководство, 2-е издание. - Пер. с англ. - СПб.: Символ- Плюс, 2010. - 560 е., ил.