Django Rest Framework: Dynamically return subset of fields

django rest framework serializer
django rest framework hidden field
django rest framework related fields
django serializer fields
django rest framework filefield
view_name django rest framework
nested serializer django
django rest framework combine serializers
Problem

As recommended in the blogpost Best Practices for Designing a Pragmatic RESTful API, I would like to add a fields query parameter to a Django Rest Framework based API which enables the user to select only a subset of fields per resource.

Example

Serializer:

class IdentitySerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = models.Identity
        fields = ('id', 'url', 'type', 'data')

A regular query would return all fields.

GET /identities/

[
  {
    "id": 1,
    "url": "http://localhost:8000/api/identities/1/",
    "type": 5,
    "data": "John Doe"
  },
  ...
]

A query with the fields parameter should only return a subset of the fields:

GET /identities/?fields=id,data

[
  {
    "id": 1,
    "data": "John Doe"
  },
  ...
]

A query with invalid fields should either ignore the invalid fields or throw a client error.

Goal

Is this possible out of the box somehow? If not, what's the simplest way to implement this? Is there a 3rd party package around that does this already?

You can override the serializer __init__ method and set the fields attribute dynamically, based on the query params. You can access the request object throughout the context, passed to the serializer.

Here is a copy&paste from Django Rest Framework documentation example on the matter:

from rest_framework import serializers

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        fields = self.context['request'].query_params.get('fields')
        if fields:
            fields = fields.split(',')
            # 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 UserSerializer(DynamicFieldsModelSerializer, serializers.HyperlinkedModelSerializer):

    class Meta:
        model = User
        fields = ('url', 'username', 'email')

dbrgn/drf-dynamic-fields: Dynamically select only a subset , Dynamically select only a subset of fields per DRF resource, either using a whitelist or a blacklist. Dynamic Serializer Fields for Django REST Framework. Questions: Problem As recommended in the blogpost Best Practices for Designing a Pragmatic RESTful API, I would like to add a fields query parameter to a Django Rest Framework based API which enables the user to select only a subset of fields per resource.

This functionality is available from a 3rd-party package.

pip install djangorestframework-queryfields

Declare your serializer like this:

from rest_framework.serializers import ModelSerializer
from drf_queryfields import QueryFieldsMixin

class MyModelSerializer(QueryFieldsMixin, ModelSerializer):
    ...

Then the fields can now be specified (client-side) by using query arguments:

GET /identities/?fields=id,data

Exclusion filtering is also possible, e.g. to return every field except id:

GET /identities/?fields!=id

disclaimer: I'm the author/maintainer.

Serializers, Here's the use case, I need to add some extra fields to my serializer depending on a request. For example, if the query string contains  Dynamically modifying serializer fields in Django Rest Framework 104 Django Rest Framework - Could not resolve URL for hyperlinked relationship using view name “user-detail”

serializers.py
class DynamicFieldsSerializerMixin(object):

    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(DynamicFieldsSerializerMixin, self).__init__(*args, **kwargs)

        if fields is not None:
            # 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 UserSerializer(DynamicFieldsSerializerMixin, serializers.HyperlinkedModelSerializer):

    password = serializers.CharField(
        style={'input_type': 'password'}, write_only=True
    )

    class Meta:
        model = User
        fields = ('id', 'username', 'password', 'email', 'first_name', 'last_name')


    def create(self, validated_data):
        user = User.objects.create(
            username=validated_data['username'],
            email=validated_data['email'],
            first_name=validated_data['first_name'],
            last_name=validated_data['last_name']
        )

        user.set_password(validated_data['password'])
        user.save()

        return user
views.py
class DynamicFieldsViewMixin(object):

 def get_serializer(self, *args, **kwargs):

    serializer_class = self.get_serializer_class()

    fields = None
    if self.request.method == 'GET':
        query_fields = self.request.QUERY_PARAMS.get("fields", None)

        if query_fields:
            fields = tuple(query_fields.split(','))


    kwargs['context'] = self.get_serializer_context()
    kwargs['fields'] = fields

    return serializer_class(*args, **kwargs)



class UserList(DynamicFieldsViewMixin, ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

Django REST Framework: Dynamic Fields in Serializers, Problem As recommended in the blogpost Best Practices for Designing a Pragmatic RESTful API, I would like to add a fields query parameter to a Django Rest  I'm developing an API with Django Rest framework, and I would like to dynamically remove the fields from a serializer. The problem is that I need to remove them depending on the value of another field.

Configure a new pagination serializer class
from rest_framework import pagination, serializers

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)


# Set the pagination serializer setting
REST_FRAMEWORK = {
    # [...]
    'DEFAULT_PAGINATION_SERIALIZER_CLASS': 'DynamicFieldsPaginationSerializer',
}
Make dynamic serializer
from rest_framework import serializers

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)
# Use it
class MyPonySerializer(DynamicFieldsModelSerializer):
    # [...]
Last, use a homemage mixin for your APIViews
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)

class MyPonyList(DynamicFields, generics.ListAPIView):
    # [...]
Request

Now, when you request a resource, you can add a parameter fields to show only specified fields in url. /?fields=field1,field2

You can find a reminder here : https://gist.github.com/Kmaschta/e28cf21fb3f0b90c597a

Django Rest Framework: Dynamically return subset of fields, Django Rest Framework: Dynamically return subset of fields a fields query parameter to a Django Rest Framework based API which enables  As recommended in the blogpost Best Practices for Designing a Pragmatic RESTful API, I would like to add a fields query parameter to a Django Rest Framework based API which enables the user to select only a subset of fields per resource. Example. Serializer: class IdentitySerializer (serializers. HyperlinkedModelSerializer): class Meta: model

Such functionality we've provided in drf_tweaks / control-over-serialized-fields.

If you use our serializers, all you need is to pass ?fields=x,y,z parameter in the query.

drf-dynamic-fields · PyPI, REST framework's serializers work very similarly to Django's Form and If we don't define this method, then deserializing data will simply return a dictionary of items. If you need to customize the serialized value of a particular field, you can do If you only want a subset of the default fields to be used in a model serializer​,  This package provides a mixin that allows the user to dynamically select only a subset of fields per resource. Official version support: Django 1.11, 2.0, 2.1; Supported REST Framework versions: 3.8, 3.9; Python 2.7 (deprecated), 3.4+ NOTE: Python 2 support is deprecated and will be removed in version 0.4.

Django Rest Framework: Dynamically return subset of fields , Dynamic fields in Django Rest Framwork serializers An obvious choice for this is to create a method that returns the age calculated based on the dob field value. as if it is a field of a model by Django and Django Rest Framework serializer. This is the last Django REST Framework release that will support Python 2. Be sure to upgrade to Python 3 before upgrading to Django REST Framework 3.10. Adjusted the compat check for django-guardian to allow the last guardian version (v1.4.9) compatible with Python 2.

Serializers - Django REST framework, Flexible, dynamic fields and nested models for Django REST Framework serializers. users/?expand=organization,friends ); Select a subset of fields by either: 'employer'): queryset = queryset.select_related('employer') return queryset. This package provides a mixin that allows the user to dynamically select only a subset of fields per resource. Official version support: Django 1.11, 2.0, 2.1; Supported REST Framework versions: 3.8, 3.9; Python 2.7 (deprecated), 3.4+ NOTE: Python 2 support is deprecated and will be removed in version 0.4. Installing pip install drf-dynamic-fields

Creating dynamic fields for django models that work with django rest , null ¶ Field.null¶ If True, Django will store empty values as NULL in the database. Default is False.. Avoid using null on string-based fields such as CharField and TextField.If a string-based field has null=True, that means it has two possible values for “no data”: NULL, and the empty string.

Comments
  • I finally came around to implement this, and it works perfectly! Thanks. I ended up writing a mixin for this, composition is a bit more flexible than subclassing :) gist.github.com/dbrgn/4e6fc1fe5922598592d6
  • You'll need to change QUERY_PARAMS to query_params in recent versions of Django, but other than that this works like a charm.
  • You probably should check that requests exists as a member of context. While it does in production it doesn't when running unit tests that create the objects manually.
  • FYI: This example is a verbatim copy of DRF documentation found here: django-rest-framework.org/api-guide/serializers/#example It's a bad form to not provide link to original authors
  • The DRF documentation, from which this answer was copied, has been improved since this answer was posted.
  • Hi. What is the difference between this and github.com/dbrgn/drf-dynamic-fields (as linked in the comments of the chosen answer)?
  • Thanks, I had a look at that implementation, and it looks like it's the same basic idea. But the dbrgn implementation has some differences: 1. doesn't support exclude with fields!=key1,key2. 2. also modifies serializers outside of GET request context, which can and will break some PUT/POST requests. 3. does not accumulate fields with e.g. fields=key1&fields=key2, which is a nice-to-have for ajax apps. It also has zero test coverage, which is somewhat unusual in OSS.
  • @wim Which versions of DRF and Django does your library support? I didn't find anything in the docs.
  • Django 1.7-1.11+, basically any configuration that DRF supports. This comment might go out of date, so check the test matrix for the CI, here.
  • Works great for me: Django==2.2.7, djangorestframework==3.10.3, djangorestframework-queryfields==1.0.0