Last active
April 5, 2022 14:03
-
-
Save ankitml/fc8f4cf30ff40e19eae6 to your computer and use it in GitHub Desktop.
Pluggable filters for Django Rest Framework
This file contains 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
Accompanies (http://iank.it/pluggable-filters-for-django-rest-framework/) | |
class FiltersBackendBase: | |
""" | |
Base class to create FilterBackends | |
FilterBackends are complementary classes that can be | |
used with GenericFilterMixin | |
""" | |
def __init__(self, request): | |
self.request = request | |
def rule(self): | |
""" | |
override this for conditional application of filter | |
eg. when a viewsets should apply a filter only for list view | |
""" | |
return True | |
class GenericFilterMixin: | |
def get_q_object(self): | |
all_keys = self.request.query_params.keys() | |
if not bool(all_keys): | |
return None | |
filter_keys = [key for key in all_keys if key in self.filter_backend.mapping] | |
q = Q() | |
for key in filter_keys: | |
value = self.request.query_params[key] | |
q = q & getattr(self.filter_backend, self.filter_backend.mapping[key])(value) | |
return q | |
def get_queryset(self): | |
queryset = self.queryset | |
self.filter_backend = self.filter_class(self.request) | |
if self.filter_backend.rule(): | |
# apply filters if rule passes.. | |
q_filter = self.get_q_object() | |
if q_filter: | |
queryset = queryset.filter(q_filter) | |
return queryset | |
class SomeFiltersBackend(FiltersBackendBase): | |
""" | |
Filter backend class to compliment GenericFilterMixin from utils/mixin. | |
""" | |
mapping = {'owner': 'filter_by_owner', | |
'catness': 'filter_by_catness', | |
'context': 'filter_by_context'} | |
def rule(self): | |
return resolve(self.request.path_info).url_name == 'pet-owners-list' | |
def filter_by_catness(self, value): | |
""" | |
A simple filter to display owners of pets with high catness, canines excuse. | |
""" | |
catness = self.request.query_params.get('catness') | |
return Q(owner__pet__catness__gt=catness) | |
def filter_by_owner(self, value): | |
if value == 'me': | |
return Q(owner=self.request.user.profile) | |
elif value.isdigit(): | |
try: | |
profile = PetOwnerProfile.objects.get(user__id=value) | |
except PetOwnerProfile.DoesNotExist: | |
raise ValidationError('Owner does not exist') | |
return Q(owner=profile) | |
else: | |
raise ValidationError('Wrong filter applied with owner') | |
def filter_by_context(self, value): | |
""" | |
value = {"context_type" : "context_id or context_ids separated by comma} | |
""" | |
import json | |
try: | |
context = json.loads(value) | |
except json.JSONDecodeError as e: | |
raise ValidationError(e) | |
context_type, context_ids = context.items() | |
context_ids = [int(i) for i in context_ids] | |
if context_type == 'default': | |
ids = context_ids | |
else: | |
ids = Context.get_ids_by_unsupported_contexts(context_type, context_ids) | |
else: | |
raise ValidationError('Wrong context type found') | |
return Q(context_id__in=ids) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment