Search_form¶
Scopo¶
Rimpiazzare la ricerca semplice dell’admin di Django con una ricerca selettiva per campi.
Scenario¶
una patch di sicurezza del 23/12/2010 ha aggiunto un metodo di ModelAdmin
lookup_allowed()
che prende un lookup (eg.: user__username
) e
ritorna un booleano per sapere se può essere utilizzato o meno.
Questa patch influenza sicuramente django 1.4+ che aggiunge molte modifiche al sistema di filtri di admin.
Qui c’è un blog sul modo di bypassarlo e tanti riferimenti al problema. Djangosnippets, riporta uno snippet che affronta la questione in modo analogo.
In sintesi i filtri ammessi per default sono solo quelli inseriti nella lista
list_filters
, in altenativa si può modificare lookup_allowed().
Componenti¶
Un oggetto ChangeList e la sua derivata
jmb.core.admin.main.JmbChangeList
Questa classe ha 2 metodi rilevanti per noi:
get_filters: che prepara tutti i filtri. Noi prima di questa chiamata modifichiamo la copia dei parametri in GET in modo che siano già stati puliti dai metodi clean_* della form get_query_set: ritorna il queryset applicando i filtri La form necessaria per creare il link che verrà usato in GET. Questa form viene creata automaticamente a partire dal campo
ModelAdmin.advanced_search_fields
Un inclusion templatetag (
advanced_search_form
) che renderizza la form e che a sua volta utilizza il templateadvanced_search_form.html
e viene chiamato così:{% block advanced_search %}{% advanced_search_form cl %}{% endblock %}
Il tag riceve quindi l’oggetto
ChangeList
in argomento ed utilizza il suo metodo.cl.model_admin.get_search_form
per trovare lasearch_form
idonea.:attr:
jmb.core.admin.options.ExtendedModelAdmin.lookup_allowed
Utilizzo¶
Nella implementazione più semplice basta creare l’attributo
ModelAdmin.advanced_search_fields
come tupla di tuple con field_names:
class CertificateAdmin(ExtendedModelAdmin):
model = Certificates
advanced_search_fields = (
('start_date__gte','user'),
('user__username__icontains', 'user__last_name__icontains', ),
('status', 'description__icontains',),
)
Nel caso serva una personalizzazione più ricca è possibile utilizzare il
metodo ModelAdmin.get_filterset
e fare ritornare una classe che eredita
da :class:django_filters.Filterset
.
django-filters¶
Rispetto al pacchetto originario di django-filters
le nostre aggiunte
permettono di:
- dichiarare il lookup_type nel nome del campo. È quindi possibile
srivere
start__date__gte
per impostare come lookup_typegte
. In questo modo non è necessario dichiarare il filter in modo dichiarativo solo per l’impostazione dellookup_type
- riempire i campi con choices secondo il field dichiarato nel modello
- aggiunge ai booleani l’opzione nulla (
-----
) - quando il
lookup_type
èin
viene usato il widget di scelta multipla - quando una data ha il
lookup_type
range
viene usato un widget che permette di scegliere fra oggi, ieri, ultimi 7 giorni, ultimo mese, mese precedente, anno in corso, anno precedente.
Altri filtri¶
Nella change list compaiono i bottoni per ricerca semplice, ricerca avanzata e filtri secondo questa logica:
ricerca semplice: | |
---|---|
se definito l’attributo search_fields |
|
ricerca avanzata: | |
se definito advanced_search_fields in
modeladmin o l’attributo filterset_class |
|
filtri: | se definito l’attributo list_filter |
Personalizzazioni¶
Jumbo (per Django 1.2.7) utilizzava una JChangeList preparata per manipolare
le date utilizzando django.utils.translation.get_format_date`()
che
ora è soppiantato da django.utils.format_date
.
Con l’attuale sistema le date vengono interpretate come localizzate.
Implementazione¶
L’attuale implementazione di basa su questi elementi:
django-filters: | modificata da noi, vedi sopra |
||||||
---|---|---|---|---|---|---|---|
change_list.html: | |||||||
|
|||||||
ExtendibleModelAdmin.setup_advanced_search: | |||||||
crea il filterset a partire da
|
|||||||
ExtendibleModelAdmin.lookup_allowed: | |||||||
permette ogni |
|||||||
ExtendibleModelAdminget.changelist: | |||||||
return JmbChangeList |
|||||||
ExtendibleModelAdminget.queryset: | |||||||
Se c’è un filtro, qui viene restituito il qs generato da search_filterset.qs |
|||||||
JmbChangeList.get_filters: | |||||||
All’interno di questo metodo pulisco self.params |
|||||||
advanced_search.js: | |||||||
|