Skip to content

Instantly share code, notes, and snippets.

@thenewguy
Forked from gauravvjn/admin.py
Created June 23, 2022 14:48
Show Gist options
  • Save thenewguy/82cc29ac794009261da2cc1088690d86 to your computer and use it in GitHub Desktop.
Save thenewguy/82cc29ac794009261da2cc1088690d86 to your computer and use it in GitHub Desktop.
Use JSONField properties in Django admin filter Raw
"""
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment