drf-url-filters is a simple django app to apply filters on drf modelviewset's queryset in a clean, simple and configurable way. It also supports validations on incoming query params and their values. A beautiful python package voluptuous is being used for validations on the incoming query parameters. The best part about voluptuous is you can define your own validations as per your query params requirements.
Installation
-
Download
drf-url-filters
app package from this git repo or can be installed using python-pip likepip install drf-url-filters
. -
Add
filters
in INSTALLED_APPS of settings.py file of django project.
How it works
-
Your View or ModelViewSet should inherit
FiltersMixin
fromfilters.mixins.FiltersMixin
. -
To apply filters using
drf-url-filters
we need to configure our view to have a dict mappingfilter_mappings
which converts incoming query parameters to query you want to make on the column name on the queryset. -
Optionally, to perform any preprocessing on the incoming values for query params, add another dict
filter_value_transformations
which maps incoming query parameters to functions that should be applied to the values corresponding to them. The resultant value is used in the final filtering.
import six
from filters.schema import base_query_params_schema
from filters.validations import (
CSVofIntegers,
IntegerLike,
DatetimeWithTZ
)
# make a validation schema for players filter query params
players_query_schema = base_query_param_schema.extend(
{
"id": IntegerLike(),
"name": six.text_type, # Depends on python version
"team_id": CSVofIntegers(), # /?team_id=1,2,3
"install_ts": DatetimeWithTZ(),
"update_ts": DatetimeWithTZ(),
"taller_than": IntegerLike(),
}
)
from rest_framework import (
viewsets,
filters,
)
from .models import Player, Team
from .pagination import ResultSetPagination
from .serializers import PlayerSerializer, TeamSerializer
from .validations import teams_query_schema, players_query_schema
from filters.mixins import (
FiltersMixin,
)
class PlayersViewSet(FiltersMixin, viewsets.ModelViewSet):
"""
This viewset automatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
"""
queryset = Player.objects.prefetch_related(
'teams' # use prefetch_related to minimize db hits.
).all()
serializer_class = PlayerSerializer
pagination_class = ResultSetPagination
filter_backends = (filters.OrderingFilter,)
ordering_fields = ('id', 'name', 'update_ts')
ordering = ('id',)
# add a mapping of query_params to db_columns(queries)
filter_mappings = {
'id': 'id',
'name': 'name__icontains',
'team_id': 'teams',
'install_ts': 'install_ts',
'update_ts': 'update_ts',
'update_ts__gte': 'update_ts__gte',
'update_ts__lte': 'update_ts__lte',
'taller_than': 'height__gte',
}
filter_value_transformations = {
'taller_than': lambda val: val / 30.48 # cm to ft
}
# add validation on filters
filter_validation_schema = players_query_schema
With the use of drf-url-filters
adding a new filter on a new column is as
simple as adding a new key in the dict. Prohibitting a filter on particular
column is same as removing a key value mapping from the filter_mappings
dict.
MIT License Copyright (c) 2016 Manjit Kumar.
Special thanks to authors of voluptuous and friends cdax and saurabhjha who encourage people to contribute into open source community.
Please open an issue for support.