""" More details on the implementation and usage can be found at https://www.pyscoop.com/django-jsonfield-attributes-in-admin-filter/ """ from django.contrib import admin from django.core.exceptions import ImproperlyConfigured class JSONFieldFilter(admin.SimpleListFilter): """ Base JSONFilter class to use by individual attribute filter classes. e.g data in JSON field { "name": "Gaurav", "company": "pyscoop", "address": { "city": "Jaipur", "country": {"name": "India", "code": "IN"} } } """ model_json_field_name = None # name of the json field column in the model json_data_property_name = None # name of one attribute from json data def get_child_value_from_json_field_data(self, json_field_data): key_list = self.json_data_property_name.split('__') for key in key_list: if isinstance(json_field_data, dict): json_field_data = json_field_data[key] return json_field_data def lookups(self, request, model_admin): """ Returns a list of tuples. The first element in each tuple is the coded value for the option that will appear in the URL query. The 2nd element is the human-readable name for the option that will appear in the right sidebar. """ if self.model_json_field_name is None: raise ImproperlyConfigured(f'Filter class {self.__class__.__name__} does not specify "model_json_field_name"') if self.json_data_property_name is None: raise ImproperlyConfigured(f'Filter class {self.__class__.__name__} does not specify "json_data_property_name"') field_value_set = set() for json_field_data in model_admin.model.objects.values_list(self.model_json_field_name, flat=True): field_value_set.add(self.get_child_value_from_json_field_data(json_field_data)) return [(v, v) for v in field_value_set] def queryset(self, request, queryset): """ Returns the filtered queryset based on the value provided in the query string & retrievable via `self.value()` """ if self.value(): json_field_query = {f'{self.model_json_field_name}__{self.json_data_property_name}': self.value()} return queryset.filter(**json_field_query) else: return queryset class CompanyFilter(JSONFieldFilter): model_json_field_name = 'jsonfield' json_data_property_name = 'company' # property/field in json data title = 'Company' # for admin sidebar parameter_name = 'js_company' # Prefixing with `js_` because one might have another column named `company`, will be used in the URL query