Skip to main content

A set of viewset mixins for the Django REST Framework.

Fully type hinted — the package ships py.typed, so your type checker sees the mixin signatures.

Supported versions

Python

3.10, 3.11, 3.12, 3.13, 3.14

Django

5.2, 6.0

DRF

3.16+

Installation

pip install djangorestframework-mango

Usage

ActionMixin

It has six action methods that can be used instead of comparing self.action.

  • is_create_action()

  • is_retrieve_action()

  • is_list_action()

  • is_update_action()

  • is_partial_update_action()

  • is_destroy_action()

class ViewSet(ActionMixin, viewsets.GenericViewSet):
    queryset = Model.objects.all()
    serializer_class = ModelSerializer

    def get_queryset(self):
        queryset = super().get_queryset()

        if self.is_create_action():
            # change queryset for create
            queryset = queryset.change_for_create()
        elif self.is_retrieve_action():
            # change queryset for retrieve
            queryset = queryset.change_for_retrieve()
        elif self.is_list_action():
            # change queryset for list
            queryset = queryset.change_for_list()

        return queryset

QuerysetMixin

It finds the <action>_queryset method and runs it. Any action works, including custom @action methods. Actions without a matching method leave the queryset untouched.

class ViewSet(QuerysetMixin, viewsets.GenericViewSet):
    queryset = Model.objects.all()
    serializer_class = ModelSerializer

    # this method runs automatically when this viewset gets the create action
    def create_queryset(self, queryset):
        return queryset.change_for_create()

    # this method runs automatically when this viewset gets the list action
    def list_queryset(self, queryset):
        return queryset.change_for_list()

    # this method runs automatically when this viewset gets the partial update action
    def partial_update_queryset(self, queryset):
        return queryset.change_for_partial_update()

    # this method runs automatically when this viewset gets the update_extra_profile action
    def update_extra_profile_queryset(self, queryset):
        return queryset.change_for_update_extra_profile()

    @action(methods=['POST'], detail=True)
    def update_extra_profile(self, request, pk=None):
        # this method calls update_extra_profile_queryset() internally
        queryset = self.get_queryset()

        return Response(serializer.data)

SerializerMixin

You can define multiple serializers by action. Unmapped actions fall back to serializer_class.

class ViewSet(SerializerMixin, viewsets.GenericViewSet):
    queryset = Model.objects.all()
    serializer_class = ModelSerializer
    serializer_class_by_actions = {
        'create': {
            'v1': ModelCreateSerializerV1,
            'v2': ModelCreateSerializerV2,
        },
        'list': ModelListSerializer,
        'retrieve': ModelRetrieveSerializer,
        'update': ModelUpdateSerializer,
        'partial_update': ModelPartialUpdateSerializer,
        'destroy': ModelDestroySerializer,
        'update_extra_profile': ModelUpdateExtraProfileSerializer,
    }

    @action(methods=['POST'], detail=True)
    def update_extra_profile(self, request, pk=None):
        # self.get_serializer returns ModelUpdateExtraProfileSerializer
        serializer = self.get_serializer()

        return Response(serializer.data)

A nested dict maps by API version, so it requires a versioning scheme to be configured — otherwise ImproperlyConfigured is raised.

PermissionMixin

You can define multiple permissions by action. Unmapped actions fall back to permission_classes.

class ViewSet(PermissionMixin, viewsets.GenericViewSet):
    queryset = Model.objects.all()
    serializer_class = ModelSerializer
    permission_by_actions = {
        'create': [IsAuthenticated],
        'list': [ReadOnly],
        'retrieve': [AllowAny],
        'update': [Owner],
        'partial_update': [Owner],
        'destroy': [Owner],
        'update_extra_profile': [Owner],
    }

    @action(methods=['POST'], detail=True)
    def update_extra_profile(self, request, pk=None):
        # this method requires Owner permission
        serializer = self.get_serializer()

        return Response(serializer.data)

MangoMixin

QuerysetMixin, SerializerMixin and PermissionMixin combined.

class ViewSet(MangoMixin, viewsets.GenericViewSet):
    queryset = Model.objects.all()
    serializer_class = ModelSerializer
    serializer_class_by_actions = {'list': ModelListSerializer}
    permission_by_actions = {'destroy': [Owner]}

    def list_queryset(self, queryset):
        return queryset.change_for_list()

SessionMiddleware

Share data within a request life cycle — useful where the request is not reachable, such as a model. The session is created per thread and cleared when the request finishes, even if the view raises.

# settings.py
MIDDLEWARE = [
    ...,
    'django_rest_framework_mango.middlewares.SessionMiddleware',
]
class ViewSet(QuerysetMixin, viewsets.GenericViewSet):
    queryset = Model.objects.all()
    serializer_class = ModelSerializer

    def list_queryset(self, queryset):
        SessionMiddleware.get_session()['current_user'] = self.request.user

        return queryset

class Model(models.Model):

    @property
    def current_user(self):
        # the model cannot reach the request, so it reads what the view stored
        session = SessionMiddleware.get_session() or {}

        return session.get('current_user')

Development

Tests run against every supported Python and Django combination through tox. tox-uv downloads the interpreters, so none of them need to be installed beforehand.

uvx --with tox-uv tox                # every combination
uvx --with tox-uv tox -f py314       # Python 3.14 x Django 5.2, 6.0
uvx --with tox-uv tox -e py312-dj60  # a single combination
uvx --with tox-uv tox -e mypy        # type check

uv run --python 3.14 pytest          # quick single run, without tox

Metadata

Release files for djangorestframework-mango 0.3.0

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

Source distribution (sdist)

Source distribution for djangorestframework-mango 0.3.0
File Size Uploaded
djangorestframework_mango-0.3.0.tar.gz 7.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for djangorestframework-mango 0.3.0
File Interpreter ABI Platform
djangorestframework_mango-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 13.5 kB

Release files / djangorestframework_mango-0.3.0.tar.gz

Download URL djangorestframework_mango-0.3.0.tar.gz
Size 7.1 kB
Tags Source
SHA-256 checksum
How to use checksums
7149daf795c6e97e50c392c4a9150e86c2a6bac190a26d08c5e2320f364123f1
BLAKE2b-256 checksum
How to use checksums
ddcc1a0f056c34d43edf0f4548dd5246f774eb1f9f414ae6bfb6456c2a242a0e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 6, 2026.

Transparency log

Release files / djangorestframework_mango-0.3.0-py3-none-any.whl

Download URL djangorestframework_mango-0.3.0-py3-none-any.whl
Size 6.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
903f4c82e3f825b7f916a1818cdf231e93f4182070c0f3376db6419595c08a76
BLAKE2b-256 checksum
How to use checksums
7b3c1558548d553d15c967942a34518a2009625b82f54ffe8d1ead79972956a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.1

1 release file

0.1

1 release file

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