Django
Niestandardowi menedżerowie i zestawy zapytań
Szukaj…
Definiowanie podstawowego menedżera za pomocą zestawów zapytań i metody `as_manager`
Menedżer Django to interfejs, przez który model django wysyła zapytanie do bazy danych. Pole objects
używane w większości zapytań django jest tak naprawdę domyślnym menedżerem utworzonym dla nas przez django (jest on tworzony tylko wtedy, gdy nie zdefiniujemy niestandardowych menedżerów).
Dlaczego mielibyśmy definiować niestandardowego menedżera / zestaw zapytań?
Aby uniknąć pisania typowych zapytań w całej naszej bazie kodu i zamiast tego odsyłania ich za pomocą łatwiejszej do zapamiętania abstrakcji. Przykład: sam zdecyduj, która wersja jest bardziej czytelna:
-
User.objects.filter(is_active=True)
tylko wszystkich aktywnych użytkowników:User.objects.filter(is_active=True)
vsUser.manager.active()
- Pobierz wszystkich aktywnych dermatologów na naszej platformie:
User.objects.filter(is_active=True).filter(is_doctor=True).filter(specialization='Dermatology')
vsUser.manager.doctors.with_specialization('Dermatology')
Kolejną korzyścią jest to, że jeśli jutro zdecydujemy, że wszyscy psychologists
są również dermatologists
, możemy łatwo zmodyfikować zapytanie w naszym menedżerze i wykonać to.
Poniżej znajduje się przykład tworzenia niestandardowego Manager
zdefiniowanego przez utworzenie QuerySet
i użycie metody 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
Dodamy go do naszego modelu, jak poniżej:
class Profile(models.Model):
...
manager = ProfileManager()
UWAGA : Po zdefiniowaniu manager
w naszym modelu, objects
nie będą już definiowane dla modelu.
select_related dla wszystkich zapytań
Model z ForeignKey
Będziemy pracować z tymi modelami:
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)
Załóżmy, że często (zawsze) uzyskujemy dostęp do book.author.name
Z uwagi
Za każdym razem możemy skorzystać z następujących
books = Book.objects.select_related('author').all()
Ale to nie jest SUCHE.
Menedżer niestandardowy
class BookManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
return qs.select_related('author')
class Book(models.Model):
...
objects = BookManager()
Uwaga : wywołanie super
musi być zmienione dla Pythona 2.x
Teraz wszystko, czego musimy użyć w widokach, to
books = Book.objects.all()
i nie będzie żadnych dodatkowych zapytań w szablonie / widoku.
Zdefiniuj niestandardowych menedżerów
Bardzo często zdarza się, że mamy do czynienia z modelami, które mają coś w rodzaju published
pola. Tego rodzaju pola są prawie zawsze używane podczas wyszukiwania obiektów, dzięki czemu można znaleźć coś takiego:
my_news = News.objects.filter(published=True)
zbyt wiele razy. Możesz użyć niestandardowych menedżerów, aby poradzić sobie z tymi sytuacjami, aby następnie napisać coś takiego:
my_news = News.objects.published()
który jest ładniejszy i łatwiejszy do odczytania również przez innych programistów.
Utwórz plik managers.py
w katalogu aplikacji i zdefiniuj nową klasę 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)
użyj tej klasy, ponownie definiując właściwość objects
w klasie modelu:
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()
Teraz możesz otrzymywać publikowane wiadomości w ten sposób:
my_news = News.objects.published()
i możesz także wykonać więcej filtrowania:
my_news = News.objects.published(title__icontains='meow')