### Navigation

- index
- modules
- toc
- next
- previous
- jmb.core 0.8.6 documentation »
- Django: aggiunte e standardizzazioni. »
- Addon & layout »

# 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 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`

## 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_type `gte`. In questo modo non è necessario dichiarare il filter in modo dichiarativo solo per l’impostazione del `lookup_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:
| 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 ): 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
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:
| gestione di visibilità advanced_search_form serialize dei soli campi non vuoti

### Navigation

- index
- modules
- toc
- next
- previous
- jmb.core 0.8.6 documentation »
- Django: aggiunte e standardizzazioni. »
- Addon & layout »