Skip to main content

Dynamic serializer configuration for Django REST Framework - Shape your API responses at runtime.drf-shapeless-serializers revolutionizes API development by giving you runtime serializer superpowers. Instead of creating multiple serializer classes , configure everything on the fly with one serializer to rule them all.Now you can shape your serializers like Rubik's Cube - rearranging fields, nesting relationships, and transforming outputs dynamically with unlimited flexibility.

Project description

DRF-Shapeless-Serializers Package

Motivation

Tired of serializer hell? Every Django REST Framework developer knows the pain of creating countless serializer variations for slightly different API endpoints, duplicating code for simple field variations, struggling with rigid and complex nested relationships, and maintaining sprawling serializer classes.

What if you could eliminate 80% of your serializer code? drf-shapeless-serializers revolutionizes API development by giving you runtime serializer superpowers. Instead of creating multiple serializer classes , configure everything on the fly with one serializer to rule them all. Now you can shape your serializers like Lego cubes - rearranging fields, nesting relationships, and transforming outputs dynamically with unlimited flexibility.

Overview

drf-shapeless-serializers provides powerful mixins that extend Django REST Framework's serializers with dynamic configuration capabilities. By inheriting from our base classes, you can select fields at runtime, rename output keys dynamically, modify field attributes per-request, add and configure nested relationships on-the-fly and apply conditional field logic. All without creating multiple serializer classes and annoying nested relations.

Installation

pip install drf-shapeless-serializers

**Add to your Django settings:

INSTALLED_APPS = [
    # ... other apps
    'shapeless_serializers',
]

Usage

Basic Setup

  1. Define your shapeless serializer:
from shapeless_serializers.serializers import ShapelessModelSerializer
  
class UserSerializer(ShapelessModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

class AuthorSerializer(ShapelessModelSerializer):
    class Meta:
        model = Author
        fields = '__all__'

class BookSerializer(ShapelessModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'
  1. Configure dynamically in views:
def book_detail(request, pk):
    book = Book.objects.get(pk=pk)
    serializer = BookSerializer(
        book,
        fields=['id', 'title', 'price', 'author'],
        rename_fields={
            'price': 'retail_price',
            'id': 'book_id'
        },
        nested={
            'author': {
                'serializer': AuthorSerializer,
                'fields': ['id', 'bio', 'user'],
                'rename_fields': {'bio': 'biography'},
                'nested': {
                    'user': {
                        'serializer': UserSerializer,
                        'fields': ['id','username', 'email'],
                    }
                }
            }
        }
    )
    return Response(serializer.data)

Feature Highlights

1. Field Selection

The fields parameter lets you cherry-pick exactly which fields to include in the output

AuthorSerializer(
    author,
    fields=['id', 'name', 'birth_date']
)

2. Field Attributes

Pass the standard DRF serializers params in run-time

AuthorSerializer(
    author,
    field_attributes={
        'bio': {'help_text': 'Author biography'}
    }
)

3. Field Renaming

rename_fields allows you to customize the output keys without changing your models.

BookSerializer(
    book,
    rename_fields={
        'price': 'retail_price',  # Output will show 'retail_price' instead of 'price'
        'id': 'book_id'
    }
)

4. Nested Relationships

The nested serializer configuration provides ultimate flexibility for relationships. You can define unlimited nesting levels while maintaining full control over each level's behavior. The configuration supports all standard DRF parameters such as read_only or instance alongside this package-specific features, allowing you to mix and match functionality as needed. Each nested serializer can itself be configured with fields selection, renaming, and even deeper nesting - creating truly dynamic relationship trees that adapt to your API requirements.

AuthorSerializer(
    author,
    nested={
        'books': {
            'serializer': BookSerializer,
            'fields': ['title', 'publish_year'],
            'nested': {
                'publisher': {
                    'serializer': PublisherSerializer,
                    'fields': ['name', 'country']
                }
            }
        }
    }
)

For complex nested structures, you can build and config relationships as deep as your API requires:

آ serializer = DynamicBlogPostSerializer(
آ  آ  آ  آ  آ  آ  self.post1,
آ  آ  آ  آ  آ  آ  fields=["id", "title", "author", "comments"],
آ  آ  آ  آ  آ  آ  rename_fields={"id": "post_identifier"},
آ  آ  آ  آ  آ  آ  nested={
آ  آ  آ  آ  آ  آ  آ  آ  "author": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer": DynamicAuthorProfileSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": ["bio", "is_verified"],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "rename_fields": {"bio": "author_biography"},
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "field_attributes": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "is_verified": {"help_text": "Verified status"}
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  },
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "nested": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "user": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer": UserSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": ["id", "username"],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "rename_fields": {"username": "user_login"},
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  }
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  },
آ  آ  آ  آ  آ  آ  آ  آ  },
آ  آ  آ  آ  آ  آ  آ  آ  "comments": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer": DynamicCommentSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": ["id", "content", "user", "replies"],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "instance": self.post1.comments.filter(
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  is_approved=True, parent__isnull=True
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  ),
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "rename_fields": {"content": "comment_text"},
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "field_attributes": {"id": {"label": "Comment ID"}},
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "nested": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "user": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer": UserSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": ["id", "username"],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "rename_fields": {"username": "commenter_name"},
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  },
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "replies": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer": DynamicCommentSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": ["id", "content", "user"],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "instance": lambda instance, ctx: instance.replies.filter(is_approved=True)
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "rename_fields": {"content": "reply_text"},
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "field_attributes": {"id": {"label": "Reply ID"}},
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "nested": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "user": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer": UserSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": ["id", "username"],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "rename_fields": {"username": "replier_name"},
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  }

آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  },

آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  },

آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  },

آ  آ  آ  آ  آ  آ  آ  آ  },

آ  آ  آ  آ  آ  آ  },

آ  آ  آ  آ  )

even the very complex and deep relations are supported:

serializer = DynamicBlogPostSerializer(
آ  آ  آ  آ  آ  آ  self.post,
آ  آ  آ  آ  آ  آ  fields=["id", "title", "author", "tags", "comments", "likes"],
آ  آ  آ  آ  آ  آ  nested={
آ  آ  آ  آ  آ  آ  آ  آ  "author": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer": DynamicAuthorProfileSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": ["id", "bio", "user"],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "nested": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "user": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer": UserSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": [
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "id",
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "email",
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  ],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "nested": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "author_profile": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer": DynamicAuthorProfileSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": ["bio"],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "nested": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "blog_posts": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer":DynamicBlogPostSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": ["title"],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "nested": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "tags": {
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "serializer": TagSerializer,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "fields": ["name"],
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  "many":True,
آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  }

آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  },

آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  }

آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  },

آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  }

آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  },

آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  }

آ  آ  آ  آ  آ  آ  آ  آ  آ  آ  },

آ  آ  آ  آ  آ  آ  آ  آ  },
آ  آ  آ  آ  آ  آ  آ )

5. Conditional Fields

Choose the fields that will appear based on conditions easily:

AuthorSerializer(
    author,
    conditional_fields={
        'email': lambda instance, ctx: ctx['request'].user.is_staff
    }
)

WHEN TO USE

  • Building public APIs with multiple versions
  • Projects needing different views of the same data
  • Rapidly evolving API requirements
  • Any Django REST Framework project tired of serializer bloat

Contributing

We welcome contributions! please check the CONTRIBUTING.md file

License

This project is licensed under the MIT License. See the LICENSE file for details.

Acknowledgements

Inspired by the flexibility needs of complex API systems. Special thanks to the Django REST Framework community for their foundational work .

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

drf_shapeless_serializers-1.0.1.tar.gz (5.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

drf_shapeless_serializers-1.0.1-py3-none-any.whl (4.4 kB view details)

Uploaded Python 3

File details

Details for the file drf_shapeless_serializers-1.0.1.tar.gz.

File metadata

File hashes

Hashes for drf_shapeless_serializers-1.0.1.tar.gz
Algorithm Hash digest
SHA256 a3b4c37d74021ed189ac5b2b2684447a85f092e5d23e2c28b93a413fbc92095f
MD5 a8b81eaf921bab87bc9f65db12fc45e3
BLAKE2b-256 bd9410bc10ff22aff067f97466cc98905de3c4b11b0460b10ae931664944137f

See more details on using hashes here.

File details

Details for the file drf_shapeless_serializers-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for drf_shapeless_serializers-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ed390eb4c857628b85a578821381035ede59997fcc19f3571f7f30326b11b72b
MD5 61bde6ff451d22e2846a23525230af46
BLAKE2b-256 3387e3b105dc9667abf39020bcfed3e7f74b4b398bf47ef19f82be3aae23c45e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page