Django
Gestori e Queryys personalizzati
Ricerca…
Definire un manager di base usando Querysets e il metodo `as_manager`
Django manger è un'interfaccia attraverso la quale il modello django interroga il database. Il campo degli objects
usato nella maggior parte delle query di django è in realtà il gestore predefinito creato per noi da django (questo viene creato solo se non definiamo i gestori personalizzati).
Perché dovremmo definire un gestore personalizzato / queryset?
Per evitare di scrivere query comuni su tutto il nostro codebase e invece di riferirle usando un'astrazione più facile da ricordare. Esempio: decidi tu stesso quale versione è più leggibile:
- Ottieni solo tutti gli utenti attivi:
User.objects.filter(is_active=True)
vsUser.manager.active()
- Ottieni tutti i dermatologi attivi sulla nostra piattaforma:
User.objects.filter(is_active=True).filter(is_doctor=True).filter(specialization='Dermatology')
vsUser.manager.doctors.with_specialization('Dermatology')
Un altro vantaggio è che se domani decidiamo che tutti gli psychologists
sono anche dermatologists
, possiamo facilmente modificare la query nel nostro manager e farla finita.
Di seguito è riportato un esempio di creazione di un Manager
personalizzato definito creando un QuerySet
e utilizzando il metodo 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
Lo aggiungeremo al nostro modello come di seguito:
class Profile(models.Model):
...
manager = ProfileManager()
NOTA : una volta definito un manager
sul nostro modello, gli objects
non saranno più definiti per il modello.
select_related per tutte le query
Modello con ForeignKey
Lavoreremo con questi modelli:
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)
Supponiamo di accedere (sempre) spesso a book.author.name
In vista
Potremmo usare quanto segue, ogni volta,
books = Book.objects.select_related('author').all()
Ma questo non è SECCO.
Manager personalizzato
class BookManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
return qs.select_related('author')
class Book(models.Model):
...
objects = BookManager()
Nota : la chiamata a super
deve essere cambiata per python 2.x
Ora tutto ciò che dobbiamo usare nelle viste è
books = Book.objects.all()
e nessuna query aggiuntiva sarà effettuata in template / view.
Definisci gestori personalizzati
Molto spesso capita di trattare con modelli che hanno qualcosa come un campo published
. Questi tipi di campi sono quasi sempre usati per recuperare oggetti, così ti troverai a scrivere qualcosa come:
my_news = News.objects.filter(published=True)
troppe volte. Puoi utilizzare i gestori personalizzati per gestire queste situazioni, in modo che tu possa scrivere qualcosa come:
my_news = News.objects.published()
che è più bello e più facile da leggere anche da altri sviluppatori.
Creare un file managers.py
nella directory app, e definire una nuova models.Manager
classe:
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)
usa questa classe ridefinendo la proprietà objects
nella classe model:
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()
Ora puoi ottenere le tue notizie pubblicate in questo modo:
my_news = News.objects.published()
e puoi anche eseguire più filtri:
my_news = News.objects.published(title__icontains='meow')