Creare filtri nelle maschere di backoffice è indispensabile per poter comodamente fruire i dati per verificare, ad esempio, le registrazioni degli utenti, le vendite di prodotti, o la prossima attività da fare. Tuttavia visualizzare un intero elenco di prodotti, seppur paginati ed ordinabili nelle colonne dei dati, molte volte non consente di avere una visione di insieme precisa e puntuale. Ad esempio, qualora si vogliono vedere i soli prodotti venduti in una certa data, non conviene estrarre le informazioni da un elenco che prevede dati anche di date differenti da quella considerata. Per aiutare la navigazione dei dati ci vengono in soccorso i filtri. Un filtro consente di scremare i dati presentati e visualizzare solo quelli necessari.
Il framework Django, attraverso Django Admin, consente di aggiungere filtri
alle proprie pagine in modo molto semplice. Attraverso i filtri è possibile
visualizzare, ad esempio, tutti i prodotti in un certo stato, tutti i contatti
che vivono a Rovigo, e così via. In Django Admin è possibile aggiungere filtri
utilizzando un list_filter
. Un list_filter
aggiunge, sulla sidebar della
pagina contenente la lista degli elementi di un determinato modello, i filtri
attivati. La pagina si presenta come segue:
Sulla parte destra della pagina si nota una colonna contenente i filtri
aggiunti con list_filter
. In questo articolo vedrai come aggiungere tali
filtri.
Definire un list_filter
Un list_filter
è aggiunto, come tupla o lista di elementi, all'interno del
ModelAdmin
di un Model
.
La definizione come tupla è:
from django.contrib import admin
class ProdottoAdmin(admin.ModelAdmin)
list_filter = ()
La definizione come lista è:
from django.contrib import admin
class ProdottoAdmin(admin.ModelAdmin)
list_filter = []
Ogni elemento deve appartenere ad una delle seguenti categorie:
- Filtro sul nome dei campi del
Model
- Filtro come classe che estende da
SimpleListFilter
- Filtro su tipi predefiniti (vedremo l'esempio del
BooleanFieldListFilter
) - Filtro su nome dei campi del tipo
RelatedOnlyFieldListFilter
Nel seguito dell'articolo andremo a specificare i tipi indicati nell'elenco.
da campi del Model
L'elemento definisce il nome del campo del Model
al quale associare il
filtro. Il filtro mostra tutti i valori, non duplicati, presenti all'interno
del campo considerato.
Qualora il filtro risulti applicato su una
ForeignKey
, esso mostra tutti gli elementi presenti sul modello
collegato, ed anche quelli che non hanno associazioni con elementi del modello sul
quale il filtro è associato. Questo comportamento si differenzia dal
comportamento del filtro RelatedOnlyFieldListFilter
, che mostra
solamente le tuple che hanno tuple associate sulla tabella sulla quale il
filtro è applicato.
L'elemento può applicare il filtro ai seguenti campi del Model
:
BooleanField
CharField
DateField
DateTimeField
IntegerField
ForeignKey
ManyToManyField
Un esempio di definizione è la seguente:
from django.contrib import admin
class ProdottoAdmin(admin.ModelAdmin)
list_filter = ('status', 'marca', )
I nomi presenti nella dichiarazione list_filter
possono contenere campi
di altri modelli collegati al modello tramite relazione. Per utilizzare campi
specifici di altri modelli si usa la notazione __
.
from django.contrib import admin
class ProdottoAdmin(admin.ModelAdmin)
list_filter = ('marca__nome', )
da SimpleListFilter
Un elemento del filtro che estende dalla classe SimpleListFilter
consente di creare filtri personalizzati di elevata complessità. Filtri di
questo tipo prevedono la gestione della query da eseguire sui dati per
filtrare le tuple sul backoffice.
La definizione del filtro all'interno del ModelAdmin
è la seguente:
list_display = [MioFiltroListFilter]
La definizione della classe prevede l'estensione dalla classe
admin.SimpleListFilter
come segue:
from django.contrib import admin
class MioFiltroListFilter(admin.SimpleListFilter):
title = ''
parameter_name = ''
def lookups(self, request, model_admin):
pass
def queryset(self, request, queryset):
pass
Il blocco di codice precedente evidenzia la segnatura necessaria per creare un
filtro di questo tipo. La classe filtro creata deve avere un proprio
title
che rappresenta il nome da dare al filtro (il nome comparirà
all'interno del backoffice). La classe dovrà anche definire il
parameter_name
ossia il nome del parametro con il quale il filtro
invierà i parametri alla query_string
. La classe prevede
l'override
del metodo lookups
che prevede la restituzione di
una tupla contenente n
elementi che saranno le voci che compariranno
nel filtro. Ogni elemento della tupla sarà costituito da:
(valore_query_string, nome_filtro)
Dove valore_query_string
è il valore passato dal filtro nella
query_string
al momento della richiesta; mentre nome_filtro
è
il nome associato al filtro che compare sul backoffice.
Un esempio di metodo lookups
completo è il seguente:
def lookups(self, request, model_admin):
return (
("1", "dietetico"),
("2", "normale"),
("3", "calorico"),
)
Infine, l'override
del metodo queryset
implementa le query per
filtrare i dati del modello. All'interno del metodo possiamo recuperare il
parametro passato in query_string
utilizzando la chiamata
self.value()
. Se non inseriamo alcun tipo di logica nel metodo, saranno
restituiti tutti i dati ad ogni chiamata del filtro. Un esempio di
override
è il seguente:
def queryset(self, request, queryset):
if self.value() == "1":
return queryset.filter(calorie__lt=100)
if self.value() == "2":
return queryset.filter(calorie__gte=100,calorie__lt=200)
if self.value() == "3":
return queryset.filter(calorie__gte=200)
su tipi predefiniti
Un elemento del list_filter
di questo tipo opera su tipi predefiniti.
Ad esempio se vogliamo creare un filtro per un campo del modello di tipi
BooleanField
possiamo definire il seguente elemento:
list_filter = (
('is_vegetale', admin.BooleanFieldListFilter),
)
dove is_vegetale
è il nome del campo a cui si fa riferimento.
da RelatedOnlyFieldListFilter
Tale elemento si differenzia rispetto al filtro sul nome del campo presentato in precedenza poiché, in questo caso, il filtro mostra solo le voci del modello che hanno un riferimento con il modello sul quale il filtro è applicato.
Ad esempio, supponiamo che il mio modello Tipologia
abbia i seguenti
elementi:
- suv
- utilitaria
- sportiva
e che solamente suv ed utilitaria abbiano associazioni con il modello
Auto
. Se applicassi sul ModelAdmin
di Auto
il filtro:
list_filter = (
('tipologia', admin.RelatedOnlyFieldListFilter),
)
otterrei nel filtro solamente le voci suv e utilitaria poiché sono le uniche che hanno una corrispondenza con auto.
Conclusioni
Gli esempi mostrati nell'articolo consentono di creare filtri avanzati all'interno del backoffice di Django Admin.