Менеджеры Django

Опубликовал: Saturday, February 4, 2024 в категории 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 е., ил.

Похожие посты:

Комментировать

Your email address will not be published. Required fields are marked *