DRF Multiple Settings
DRF ViewSets supporting different settings for actions
Table of Contents
Requirements
Django REST Framework 3.0+
Installation
Install using pip:
pip install drf-multiple-settings
Usage
drf-multiple-settings provides you with class GenericMultipleSettingsViewSet
which is a subclass of DRF's GenericViewSet
with added support of different settings for actions.
This ViewSet does not contain any actions, so before you using it you should inherit this class adding mixins with desired actions (e.g. mixins.RetrieveModelMixin
, mixins.ListModelMixin
to add retrieve
and list
actions)
Instead of parametrize entire viewset with serializer_class
, filterset_class
, ordering_fields
and ordering
, you should give this parameters to each action. To do so, declare next dictionaries with keys equal action names.
Serializer settings
You must provide serializer_classes
dictionary to configure serializers in views, using GenericMultipleSettingsViewSet
. This dictionary is equivalent of GenericAPIView serializer_class
field and it's value should contain values of same type.
If serializer_classes
is not provided or does not contain value for processed action ViewConfigurationError
exception will be raised
Filters settings
If you wish to use different filtersets for different actions as well (which seems logical), your ViewSet should use filter backend from drf_multiple_settings.filter_backends
package. As of now it contains only FilterBackend
which overrides django_filters.rest_framework.DjangoFilterBackend
and gives you access to filterset_classes
dictionary. This dictionary is equivalent filterset_class
field and it's value should contain values of same type. For more information on filterset_class
and django-filter
visit django-filter documentation.
If you are using filtering backend which does not have implementation in drf_multiple_settings.filter_backends
look at implementation for django-filter and write your own it's pretty straightforward. Feel free to contact me at github so I can include your implementation of other FilterBackend in package.
Ordering settings
If you wish to use different ordering setting for different actions as well (which also seems logical), your ViewSet
should use MultipleSettingsOrderingFilter
which gives you access to this dictionaries:
- Ordering fields dictionary:
ordering_fields_set
- Default ordering dictionary:
ordering_set
Each dictionary value should have type of corresponding normal GenericAPIView parameters. See Django REST Framework documentation if you unsure what it is.
get_response
method
GenericMultipleSettingsViewSet
also provides get_response method for rendering response from action using whatever data you wish using current action's settings.
def get_response(self, data, many):
This method gets QuerySet from data
parameter paginate it if needed, then serialize it using serializer, set to this action and return serialized data as Response
. Parameter many
tells serializer if it should serialize more then one element. Example of using this method can be found in Example section.
Method designed to be used inside an action-decorated methods. Usage outside actions was not tested.
ModelViewSet
and ReadonlyModelViewSet
DRF provides two default ViewSets:
-
ModelViewSet
for CRUD operations with model -
ReadOnlyModelViewSet
for read operations with model (list
andretrieve
actions)
To ease it's usage drf-multiple-settings provides GenericMultipleSettingsViewSet
subclasses with same functionality:
ModelMultipleSettingsViewSet
ReadOnlyModelMultipleSettingsViewSet
Example
For this example we assume that we have following:
- Two models Title and Issue
- Three serializers
-
TitleListSerializer
- serializer with main info about title -
TitleDetailDerializer
- serializer with detail info about title IssueListSerializer
-
- Two FilterSet classes
-
TitleFilter
- title filters -
IssueFilter
- issue filters
-
And we wish create readonly API with following url structure
-
/title/
- list of all titles -
/title/{id}
- detail info of title with id={id} -
/title/{id}/issues
- list of all issues of title with id={id}
Additionally we want to allow sorting titles by name and issues by name, number and publish_date with default ordering on name
ascending and publish_date
descending accordingly and allow user to filter results using corresponding FilterSet classes.
We can use drf-multiple-settings to implement this API as follows (views.py):
from django.shortcuts import get_object_or_404
from drf_multiple_settings.filter_backends.django_filters import FilterBackend
from drf_multiple_settings.viewsets import ReadOnlyModelMultipleSettingsViewSet, MultipleSettingsOrderingFilter
from rest_framework.decorators import action
# ... Models and serializers imports...
class TitleViewSet(ComicsDBBaseViewSet):
queryset = models.Title.objects.all()
filter_backends = (MultipleSettingsOrderingFilter, FilterBackend,)
# Serializers
serializer_classes = {
'list': TitleListSerializer,
'retrieve': TitleDetailSerializer,
'issues': IssueListSerializer
}
# FilterSets
filterset_classes = {
'list': TitleFilter,
'issues': IssueFilter
}
# Ordering Parameters
ordering_fields_set = {
'list': ("name",),
'issues': ("name", "number", "publish_date")
}
ordering_set = {
'list': ("name", ),
'issues': ("-publish_date", ),
}
@action(detail=True) # detail = True needed so DRF router include {id} in url
def issues(self, request, pk):
title = get_object_or_404(models.Title, pk=pk)
titles = title.issues.all()
titles = self.filter_queryset(titles)
return self.get_response(titles, True)