rest_framework_dyn_serializer

Dynamic serializer for Django REST framework


Keywords
Django
License
MIT
Install
pip install rest_framework_dyn_serializer==1.3.1

Documentation

DRF Dynamic Model Serializer Build Status

Intro

Dynamic model serializer designed to create more dynamic REST. Despite spherical REST in vacuum works with the full models, very often it's really inconvenient to fetch from database and pass to user the full instance. It leads to overhead or to having multiple views with different attribute sets. Having ability to specify REST endpoint which attributes to return on demand, allows us to reuse same endpoint in different cases. In some manner it's a simple replacement of GraphQL.

Installation

pip install rest_framework_dyn_serializer

Important! Serializer API may change in future, so always freeze version in requirements.txt:

Good:

rest_framework_dyn_serializer==1.0.1

Bad:

rest_framework_dyn_serializer

Actually, it makes sense for other libraries as well, just a reminder.

Usage

Define models

from django.contrib.auth.models import User
from django.db import models


class Author(models.Model):
    name = models.CharField(max_length=50)
    birth_date = models.DateField(blank=True, null=True)


class Article(models.Model):
    title = models.CharField(max_length=255)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    content = models.TextField()
    author = models.ForeignKey(Author, related_name='articles')

Define serializer

from rest_framework import views, generics, status, serializers, viewsets

from rest_framework_dyn_serializer import DynModelSerializer
from test_samples.sample.sampleapp.models import Article, Author, Review


class AuthorDynSerializer(DynModelSerializer):
    class Meta:
        model = Author
        fields_param = 'author_fields'
        fields = ['id', 'name', 'birth_date']


class ArticleDynSerializer(DynModelSerializer):
    author = AuthorDynSerializer(
        fields=['id', 'name', 'birth_date'],
        required=False
    )

    class Meta:
        model = Article
        fields_param = 'article_fields'
        fields = ['id', 'title', 'created', 'updated', 'content', 'author']

fields in init is an optional parameter to override the list of fields declared in Meta class

fields_param in Meta corresponds to list of fields, passed as coma separated GET parameter

Set view or viewset to use dynamic serializer

There are two options to make serializer dynamic. Instantiate serializer with keyword argument limit_fields = True. Keyword argument overrides limit_fields value from Meta

class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Article.objects.all().order_by('id')

    def get_serializer(self, *args, **kwargs):
        context = self.get_serializer_context()
        context['request'] = self.request
        s = ArticleDynSerializer(*args, context=context, limit_fields=True, **kwargs)
        return s

Or made serializer dynamic by default. Add limit_fields = True attribute to serializer Meta

class ArticleDynSerializer(DynModelSerializer):
    author = AuthorDynSerializer(required=False)

    class Meta:
        model = Article
        fields_param = 'article_fields'
        fields = ['id', 'title', 'created', 'updated', 'content', 'author']
        limit_fields = True

class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Article.objects.all().order_by('id') 
    serializer_class = ArticleDynSerializer

Important! Dyn serializer requires explicit limit_fields set to True to work as dynamic, otherwise it's working as ordinary model serializer. Also request parameter is required in context, otherwise it will not be able to get which parameters to load.

Important! Dyn serializer limits fields only for GET requests. For POST, PATCH and DELETE requests it's working as ordinary serializer.

Test endpoint

Default (no fields specified)

curl http://localhost:8000/article/
[
    {
        "id": 1
    },
    {
        "id": 2
    }
]

With article fields

curl http://localhost:8000/article/?article_fields=id,title,content,author
  [
    {
        "title": "Title 1",
        "content": "Lorem ipsum dolor sit amet...",
        "id": 1,
        "author": {
            "id": 1
        }
    },
    {
        "title": "Title 2",
        "content": "Lorem ipsum dolor sit amet...",
        "id": 2,
        "author": {
            "id": 1
        }
    }
]

With article and author fields

curl http://localhost:8000/article/?article_fields=id,title,content,author&author_fields=id,name
  [
    {
        "title": "Title 1",
        "content": "Lorem ipsum dolor sit amet...",
        "id": 1,
        "author": {
            "id": 1,
            "name": "John Smith"
        }
    },
    {
        "title": "Title 2",
        "content": "Lorem ipsum dolor sit amet...",
        "id": 2,
        "author": {
            "id": 1,
            "name": "John Smith"
        }
    }
]