Created
April 8, 2016 16:30
-
-
Save alukach/272584e54e85d43362dce566fe514313 to your computer and use it in GitHub Desktop.
A ModelSerializer that allows for optional fields to be added to a serializer. These fields only appear when they are referred to by name with a `include` GET parameter. Additionally, a user can provide a `fields` GET parameter to limit which fields are serialized for output.
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
from rest_framework import serializers | |
class DynamicFieldsModelSerializer(serializers.ModelSerializer): | |
""" | |
A ModelSerializer that allows for optional fields to be added to a | |
serializer. These fields only appear when they are referred to by | |
name with a `include` GET parameter. | |
Additionally, a user can provide a `fields` GET parameter to limit | |
which fields are serialized for output. | |
""" | |
def __init__(self, *args, **kwargs): | |
fields = getattr(self.Meta, 'fields', None) or self.get_fields().keys() | |
optional_fields = getattr(self.Meta, 'optional_fields', False) | |
# Combine fields and optional fields into fields attribute | |
if optional_fields: | |
if not isinstance(self.Meta.optional_fields, (list, tuple)): | |
raise Exception("'optional_fields' must be list or tuple") | |
self.Meta.fields = type(optional_fields)(fields) + self.Meta.optional_fields | |
# Instantiate the superclass normally | |
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) | |
# Don't apply field-limiting logic when deserializing data | |
request = self.context.get('request') | |
if not request: | |
return | |
fields = request.GET.getlist('fields') | |
included = request.GET.getlist('include') | |
# Drop any fields that are not specified in the `fields` argument. | |
if fields: | |
# Accept either comma-separated values or multiple GET params with same name | |
fields = [f for f in fields for f in f.split(',')] | |
allowed = set(fields) | |
existing = set(self.fields.keys()) | |
for field_name in existing - allowed: | |
self.fields.pop(field_name) | |
# Omit any optional fields that aren't specified in GET param | |
elif optional_fields: | |
# Accept either comma-separated values or multiple GET params with same name | |
included = [f for f in included for f in f.split(',')] | |
for optional_field in optional_fields: | |
if optional_field not in included: | |
self.fields.pop(optional_field) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment