-
-
Save JakubDotPy/7a5d64d9a73113d0ec2700dba4112ff4 to your computer and use it in GitHub Desktop.
Use JSONField properties in Django admin filter Raw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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": "Jakub", | |
"company": "ZF", | |
"address": { | |
"city": "Pilsen", | |
"country": {"name": "Czechia", "code": "CZ"} | |
} | |
} | |
""" | |
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] | |
@staticmethod | |
def _retype_value(value): | |
"""Tries to convert strings to integers.""" | |
if not value: | |
return value | |
try: | |
value = int(value) | |
except ValueError: | |
try: | |
value = float(value) | |
except ValueError: | |
return value | |
finally: | |
return value | |
def value(self): | |
return self._retype_value(super(JSONFieldFilter, self).value()) | |
def queryset(self, request, queryset): | |
""" | |
Returns the filtered queryset based on the value provided in the query string & retrievable via `self.value()` | |
""" | |
if value := self.value(): | |
json_field_query = {f'{self.model_json_field_name}__{self.json_data_property_name}': value} | |
return queryset.filter(**json_field_query) | |
else: | |
return queryset | |
class OsFilter(JSONFieldFilter): | |
"""Used for hardware_computerhardware filtering""" | |
model_json_field_name = 'os' | |
json_data_property_name = 'system' # property/field in json data | |
title = 'Os' # for admin sidebar | |
parameter_name = 'os_system' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment