Last active
September 5, 2020 10:31
-
-
Save Kmaschta/e28cf21fb3f0b90c597a to your computer and use it in GitHub Desktop.
Django Rest Framework - Dynamic Fields
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
# How to display only interesting fields for a Django Rest Framework API | |
# /?fields=field1,field2,field3 | |
from rest_framework import serializers, pagination | |
class DynamicFieldsModelSerializer(serializers.ModelSerializer): | |
""" | |
A ModelSerializer that takes an additional `fields` argument that | |
controls which fields should be displayed. | |
See: | |
http://tomchristie.github.io/rest-framework-2-docs/api-guide/serializers | |
""" | |
def __init__(self, *args, **kwargs): | |
# Don't pass the 'fields' arg up to the superclass | |
fields = kwargs.pop('fields', None) | |
# Instantiate the superclass normally | |
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) | |
if fields: | |
# Drop any fields that are not specified in the `fields` argument. | |
allowed = set(fields) | |
existing = set(self.fields.keys()) | |
for field_name in existing - allowed: | |
self.fields.pop(field_name) | |
class DynamicFieldsPaginationSerializer(pagination.BasePaginationSerializer): | |
""" | |
A dynamic fields implementation of a pagination serializer. | |
""" | |
count = serializers.Field(source='paginator.count') | |
next = pagination.NextPageField(source='*') | |
previous = pagination.PreviousPageField(source='*') | |
def __init__(self, *args, **kwargs): | |
""" | |
Override init to add in the object serializer field on-the-fly. | |
""" | |
fields = kwargs.pop('fields', None) | |
super(pagination.BasePaginationSerializer, self).__init__(*args, **kwargs) | |
results_field = self.results_field | |
object_serializer = self.opts.object_serializer_class | |
if 'context' in kwargs: | |
context_kwarg = {'context': kwargs['context']} | |
else: | |
context_kwarg = {} | |
if fields: | |
context_kwarg.update({'fields': fields}) | |
self.fields[results_field] = object_serializer(source='object_list', | |
many=True, | |
**context_kwarg) | |
class DynamicFields(object): | |
"""A mixins that allows the query builder to display certain fields""" | |
def get_fields_to_display(self): | |
fields = self.request.GET.get('fields', None) | |
return fields.split(',') if fields else None | |
def get_serializer(self, instance=None, data=None, files=None, many=False, | |
partial=False, allow_add_remove=False): | |
""" | |
Return the serializer instance that should be used for validating and | |
deserializing input, and for serializing output. | |
""" | |
serializer_class = self.get_serializer_class() | |
context = self.get_serializer_context() | |
fields = self.get_fields_to_display() | |
return serializer_class(instance, data=data, files=files, | |
many=many, partial=partial, | |
allow_add_remove=allow_add_remove, | |
context=context, fields=fields) | |
def get_pagination_serializer(self, page): | |
""" | |
Return a serializer instance to use with paginated data. | |
""" | |
class SerializerClass(self.pagination_serializer_class): | |
class Meta: | |
object_serializer_class = self.get_serializer_class() | |
pagination_serializer_class = SerializerClass | |
context = self.get_serializer_context() | |
fields = self.get_fields_to_display() | |
return pagination_serializer_class(instance=page, context=context, fields=fields) | |
# Howto | |
# Set the pagination serializer setting | |
REST_FRAMEWORK = { | |
# [...] | |
'DEFAULT_PAGINATION_SERIALIZER_CLASS': 'DynamicFieldsPaginationSerializer', | |
} | |
# Inherit your serializers with DynamicFieldsModelSerializer | |
class MyPonySerializer(DynamicFieldsModelSerializer): | |
# [...] | |
# Make your API Views with mixin | |
class MyPonyList(DynamicFields, generics.ListAPIView): | |
# [...] | |
# Enjoy ! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment