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, che
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: | |
il template usato è quello contenuto in jmb.core È importante che admin/change_list.html di jmb.core venga usato al posto di quello di django.contrib.admin, questo è ottenuto impostando nelle installed_apps jmb.core al primo posto (il template.loader.app_directories usa INSTALLED_APPS ) | |
advanced_search_form: | |
un templatetag che implementa la ricerca avanzata | |
jsearch_form: | un template tag che implementa la toolbar della ricerca |
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 |