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 multiplaquando 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’attributofilterset_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
- il template usato è quello contenuto in
jmb.core
È importante che
admin/change_list.html
dijmb.core
venga usato al posto di quello didjango.contrib.admin
, questo è ottenuto impostando nelleinstalled_apps
jmb.core
al primo posto (il template.loader.app_directories usa INSTALLED_APPS ): qui vengono messi 2 nuovi templatetags
- advanced_search_form
un templatetag che implementa la ricerca avanzata
- jsearch_form
un template tag che implementa la toolbar della ricerca
- il template usato è quello contenuto in
- ExtendibleModelAdmin.setup_advanced_search
crea il filterset a partire da
advanced_search_fields
osearch_filterset_class
oget_filterset__class
- ExtendibleModelAdmin.lookup_allowed
permette ogni
search_field
- 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
gestione di visibilità advanced_search_form
serialize dei soli campi non vuoti