Django
Пользовательские менеджеры и запросы
Поиск…
Определение базового менеджера с использованием Querysets и метода `as_manager`
Django manger - это интерфейс, через который модель django запрашивает базу данных. Поле objects
используемое в большинстве запросов django, фактически является менеджером по умолчанию, созданным для нас django (это создается только в том случае, если мы не определяем настраиваемых менеджеров).
Почему мы должны определить пользовательский менеджер / набор запросов?
Чтобы избежать написания общих запросов по всей нашей базе кода и вместо этого ссылаться на них, используя более легкую для запоминания абстракцию. Пример. Определите, какая версия более читаема:
- Только получить всех активных пользователей:
User.objects.filter(is_active=True)
vsUser.manager.active()
- Получить всех активных дерматологов на нашей платформе:
User.objects.filter(is_active=True).filter(is_doctor=True).filter(specialization='Dermatology')
vsUser.manager.doctors.with_specialization('Dermatology')
Еще одно преимущество заключается в том, что если завтра мы решаем, что все psychologists
также являются dermatologists
, мы можем легко изменить запрос в нашем Менеджере и сделать с ним.
Ниже приведен пример создания настраиваемого Manager
определяется путем создания QuerySet
и использования метода as_manager
.
from django.db.models.query import QuerySet
class ProfileQuerySet(QuerySet):
def doctors(self):
return self.filter(user_type="Doctor", user__is_active=True)
def with_specializations(self, specialization):
return self.filter(specializations=specialization)
def users(self):
return self.filter(user_type="Customer", user__is_active=True)
ProfileManager = ProfileQuerySet.as_manager
Мы добавим его в нашу модель, как показано ниже:
class Profile(models.Model):
...
manager = ProfileManager()
ПРИМЕЧАНИЕ . Как только мы определили manager
на нашей модели, objects
больше не будут определены для модели.
select_related для всех запросов
Модель с ForeignKey
Мы будем работать с этими моделями:
from django.db import models
class Book(models.Model):
name= models.CharField(max_length=50)
author = models.ForeignKey(Author)
class Author(models.Model):
name = models.CharField(max_length=50)
Предположим, что мы часто (всегда) book.author.name
доступ к book.author.name
Ввиду
Мы могли бы использовать следующее, каждый раз,
books = Book.objects.select_related('author').all()
Но это не СУХОЙ.
Пользовательский менеджер
class BookManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
return qs.select_related('author')
class Book(models.Model):
...
objects = BookManager()
Примечание : вызов super
должен быть изменен для python 2.x
Теперь все, что нам нужно использовать в представлениях
books = Book.objects.all()
и никаких дополнительных запросов в шаблоне / представлении не будет.
Определение пользовательских менеджеров
Очень часто приходится иметь дело с моделями, которые имеют что-то вроде published
области. Такие типы полей почти всегда используются при извлечении объектов, так что вы обнаружите, что пишете что-то вроде:
my_news = News.objects.filter(published=True)
слишком много раз. Вы можете использовать пользовательских менеджеров для решения этих ситуаций, чтобы затем вы могли написать что-то вроде:
my_news = News.objects.published()
который является более приятным и легким для чтения другими разработчиками.
Создайте файл managers.py
в каталоге приложения, и определить новый models.Manager
класс:
from django.db import models
class NewsManager(models.Manager):
def published(self, **kwargs):
# the method accepts **kwargs, so that it is possible to filter
# published news
# i.e: News.objects.published(insertion_date__gte=datetime.now)
return self.filter(published=True, **kwargs)
используйте этот класс, переопределив свойство objects
в классе модели:
from django.db import models
# import the created manager
from .managers import NewsManager
class News(models.Model):
""" News model
"""
insertion_date = models.DateTimeField('insertion date', auto_now_add=True)
title = models.CharField('title', max_length=255)
# some other fields here
published = models.BooleanField('published')
# assign the manager class to the objects property
objects = NewsManager()
Теперь вы можете получить опубликованные новости просто так:
my_news = News.objects.published()
и вы также можете выполнять большую фильтрацию:
my_news = News.objects.published(title__icontains='meow')