Skip to main content

drf-shapeless-serializers

Motivation

Traditional Django REST Framework serializers often lead to what’s known as “serializer hell” - a situation where developers:

  • Create numerous serializer variations for slightly different API endpoints
  • Duplicate code for simple field variations
  • Struggle with rigid and complex nested relationships
  • Maintain sprawling serializer classes that become hard to manage

drf-shapeless-serializers was created to solve these pain points by introducing dynamic runtime configuration capabilities, allowing you to eliminate up to 80% of your serializer code while gaining unprecedented flexibility.

Documentation

https://drf-shapeless-serializers.readthedocs.io/en/latest/

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, and add configured nested relationships on-the-fly.

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: Instead of passing dictionaries, you now pass instantiated serializers into the nested parameter, allowing for a more Pythonic and type-safe configuration.
@api_view(['GET'])
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': AuthorSerializer(
                fields=['id', 'bio', 'user'],
                rename_fields={'bio': 'biography'},
                nested={
                    'user': UserSerializer(fields=['id', 'username', 'email'])
                }
            )
        }
    )
    return Response(serializer.data)

Feature Highlights

1. Class-Based View (CBV) Support

The ShapelessViewMixin allows you to define dynamic configurations directly on your ViewSets. This keeps your view logic clean and centralized.

from shapeless_serializers.views import ShapelessViewMixin

class BookViewSet(ShapelessViewMixin, viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def get_serializer_fields(self):
        if self.action == 'list':
            return ['id', 'title', 'price']
        return ['id', 'title', 'description', 'author', 'comments']

    def get_serializer_nested(self):
        if self.action == 'retrieve':
            return {
                'author': AuthorSerializer(fields=['name', 'bio']),
                'comments': CommentSerializer(fields=['content', 'user'], many=True)
            }
        return {}

2. Field Selection

The fields parameter lets you cherry-pick exactly which fields to include.

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

3. Field Attributes

Pass standard DRF serializer params at runtime.

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

4. Nested Relationships

Nested configuration supports unlimited depth. Each level can be customized with its own fields, renaming, and attributes.

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

For extremely complex structures, the syntax remains readable:

serializer = DynamicBlogPostSerializer(
    posts,
    fields=["id", "title", "author", "comments"],
    rename_fields={"id": "post_identifier"},
    nested={
        "author": DynamicAuthorProfileSerializer(
            fields=["bio", "is_verified", "user"],
            rename_fields={"bio": "author_biography"},
            nested={
                "user": UserSerializer(
                    fields=["id", "username"],
                    rename_fields={"username": "user_login"}
                )
            }
        ),
        "comments": DynamicCommentSerializer(
            fields=["id", "content", "user", "replies"],
            instance=posts.comments.filter(is_approved=True, parent__isnull=True),
            rename_fields={"content": "comment_text"},
            nested={
                "user": UserSerializer(fields=["id", "username"]),
                "replies": DynamicCommentSerializer(
                    fields=["id", "content", "user"],
                    instance=lambda instance, ctx: instance.replies.filter(is_approved=True),
                    rename_fields={"content": "reply_text"}
                )
            }
        )
    }
)

5. Conditional Fields

Include fields based on runtime logic (like user permissions):

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

6. Inline Shapeless Model Serializers

Create serializers on-the-fly without defining a class—perfect for one-off needs:

serializer = InlineShapelessModelSerializer(
    book,
    model=Book,
    fields=['title', 'author'],
    nested={
        'author': InlineShapelessModelSerializer(
            model=Author,
            fields=['name', 'bio']
        )
    }
)

When to Use

  • Building public APIs with multiple versions.
  • Projects needing different "views" of the same data (e.g., Summary vs. Detail).
  • Rapidly evolving API requirements where creating new classes is a bottleneck.
  • Any project suffering from "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 need for high-flexibility API systems. Special thanks to the Django REST Framework community.


Support Me

If you find this package useful, please consider supporting its development:

  • USDT (TRC20): TEitNDQMm4upYmNvFeMpxTRGEJGdord3S5
  • USDT (BEP20): 0xc491a2ba6f386ddbf26cdc906939230036473f5d
  • BTC: 13X8aZ23pFNCH2FPW6YpRTw4PGxo7AvFkN

Release files for drf-shapeless-serializers 1.0.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for drf-shapeless-serializers 1.0.7
File Size Uploaded
drf_shapeless_serializers-1.0.7.tar.gz 9.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for drf-shapeless-serializers 1.0.7
File Interpreter ABI Platform
drf_shapeless_serializers-1.0.7-py3-none-any.whl Python 3 none any Details

Total release size: 19.2 kB

Release files / drf_shapeless_serializers-1.0.7.tar.gz

Download URL drf_shapeless_serializers-1.0.7.tar.gz
Size 9.2 kB
Tags Source
SHA-256 checksum
How to use checksums
40229449a68fb02d8f911870d02bb391d508d35ea6e7a03892f213f5f1140b98
BLAKE2b-256 checksum
How to use checksums
8d3844d1928dfbc395f62b99afd200b1f7e4b6129c5922759f3bb8cd8330e923
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.0

Release files / drf_shapeless_serializers-1.0.7-py3-none-any.whl

Download URL drf_shapeless_serializers-1.0.7-py3-none-any.whl
Size 10.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9f6b17c3334e0d82461da68aa13f0b8f8d51d028aa712d3b7b97d6d8d57b3f78
BLAKE2b-256 checksum
How to use checksums
971089c0f6357058814fd23eab7b3a226a586c95929d81c758e2caaf22ce7b21
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.0

Release history Release notifications | RSS feed

This release

1.0.7 This release

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page