Rimpiazzare la ricerca semplice dell’admin di Django con una ricerca selettiva per campi.
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().
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 template advanced_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 la search_form idonea.
:attr:jmb.core.admin.options.ExtendedModelAdmin.lookup_allowed
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.
Rispetto al pacchetto originario di django-filters le nostre aggiunte permettono di:
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 |
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.
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 advanced_search_fields o search_filterset_class o get_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: | |||||||
|