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?
For nested data, I am using Django Rest Framework with the package recommended in the docs, drf-flexfields
This allows you to restrict the fields returned on both the parent and child objects. The instructions in the readme are good, just a few things to watch out for:
The URL seems to need the / like this '/person/?expand=country&fields=id,name,country' instead of as written in the readme '/person?expand=country&fields=id,name,country'
The naming of the nested object and its related name need to be completely consistent, which isn't required otherwise.
If you have 'many' e.g. a country can have many states, you'll need to set 'many': True in the Serializer as described in the docs.
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.You could try Dynamic REST, which has support for dynamic fields (inclusion, exclusion), embedded / sideloaded objects, filtering, ordering, pagination, and more.
serializers.py
views.py
This functionality is available from a 3rd-party package.
Declare your serializer like this:
Then the fields can now be specified (client-side) by using query arguments:
Exclusion filtering is also possible, e.g. to return every field except id:
disclaimer: I'm the author/maintainer.
You can override the serializer
__init__
method and set thefields
attribute dynamically, based on the query params. You can access therequest
object throughout the context, passed to the serializer.Here is a copy&paste from Django Rest Framework documentation example on the matter: