diff --git a/djaa_list_filter/admin.py b/djaa_list_filter/admin.py index b37bd17..3547aff 100644 --- a/djaa_list_filter/admin.py +++ b/djaa_list_filter/admin.py @@ -97,6 +97,23 @@ class AjaxAutocompleteListFilterModelAdmin(admin.ModelAdmin): self.list_filter = list_filter super().__init__(*args, **kwargs) + # Helper che risolve i campi annidati (es. 'a__b__c') seguendo le relazioni. + # Restituisce il campo finale della catena. + # Serve per evitare che un modello admin con autocomplete_list_filter senza + # un campo non annidato non visualizzi i filtri perché non li riesce a risolvere + def _resolve_field_path(self, path: str): + model = self.model + field = None + + for part in path.split('__'): + # get_field può generare l'eccezione di FieldDoesNotExist + # viene gestita sotto nella property media con apposito try catch + field = model._meta.get_field(part) + if field.is_relation and field.related_model is not None: + model = field.related_model + + return field + @property def media(self): # I media di jQuery/select2/autocomplete sono derivati dal widget @@ -109,16 +126,18 @@ class AjaxAutocompleteListFilterModelAdmin(admin.ModelAdmin): # ancora definito) e il filtro non si agganciava: selezionando dalla tendina # non veniva applicato. widget_js, widget_css = [], {} - for field_name in getattr(self, 'autocomplete_list_filter', []): + for field_path in getattr(self, 'autocomplete_list_filter', []): try: - field = self.model._meta.get_field(field_name) + field = self._resolve_field_path(field_path) except FieldDoesNotExist: continue + # Gli asset sono identici per ogni campo autocomplete: ne basta uno. wm = AutocompleteSelect(field, self.admin_site).media widget_js = list(wm._js) widget_css = {tipo: list(files) for tipo, files in wm._css.items()} break + css = dict(widget_css) css['screen'] = css.get('screen', []) + ['djaa_list_filter/admin/css/autocomplete_list_filter.css'] extra = forms.Media(