{"id":4933,"library":"djangorestframework-role-filters","title":"Django REST Framework Role Filters","description":"djangorestframework-role-filters is a Python library that provides simple and declarative role-based filtering for Django REST Framework views and querysets. It aims to eliminate the need for verbose 'if-else' statements in view logic by centralizing role definitions. The current version is 1.1.0, with releases occurring periodically, typically to update compatibility with newer Django/DRF versions.","status":"active","version":"1.1.0","language":"en","source_language":"en","source_url":"https://github.com/allisson/django-rest-framework-role-filters","tags":["django","rest framework","drf","roles","permissions","filtering","authorization"],"install":[{"cmd":"pip install djangorestframework-role-filters","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Required for any Django project.","package":"Django","optional":false},{"reason":"Core dependency for building REST APIs in Django.","package":"djangorestframework","optional":false}],"imports":[{"note":"Base class for defining role-specific filtering logic.","symbol":"RoleFilter","correct":"from rest_framework_role_filters.role_filters import RoleFilter"},{"note":"Viewset that integrates role-based filtering.","symbol":"RoleFilterModelViewSet","correct":"from rest_framework_role_filters.viewsets import RoleFilterModelViewSet"}],"quickstart":{"code":"import os\nfrom django.db import models\nfrom django.contrib.auth.models import AbstractUser\nfrom rest_framework import serializers\nfrom rest_framework_role_filters.role_filters import RoleFilter\nfrom rest_framework_role_filters.viewsets import RoleFilterModelViewSet\n\n# --- Mock Django Setup (for runnable example) ---\n# This is usually handled by a real Django project setup\nos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') # Replace with your actual settings\nimport django\ndjango.setup()\n\n# --- Mock Models ---\nclass User(AbstractUser):\n    ROLE_CHOICES = (\n        ('admin', 'Admin'),\n        ('user', 'User'),\n    )\n    role = models.CharField(max_length=10, choices=ROLE_CHOICES, default='user')\n\nclass Post(models.Model):\n    title = models.CharField(max_length=255)\n    body = models.TextField()\n    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')\n    created_at = models.DateTimeField(auto_now_add=True)\n    updated_at = models.DateTimeField(auto_now=True)\n\n    def __str__(self):\n        return self.title\n\n# --- Mock Serializers ---\nclass PostSerializer(serializers.ModelSerializer):\n    class Meta:\n        model = Post\n        fields = ['id', 'title', 'body', 'user', 'created_at', 'updated_at']\n        read_only_fields = ['user']\n\nclass PostSerializerForUser(serializers.ModelSerializer):\n    class Meta:\n        model = Post\n        fields = ['id', 'title', 'body', 'created_at', 'updated_at']\n        read_only_fields = ['user']\n\n# --- Role Filters (role_filters.py) ---\nclass AdminRoleFilter(RoleFilter):\n    role_id = 'admin'\n\n    def get_allowed_actions(self, request, view, obj=None):\n        # Admins can do anything\n        return ['create', 'list', 'retrieve', 'update', 'partial_update', 'destroy']\n\n    def get_queryset(self, request, view, queryset):\n        # Admins see all posts\n        return queryset.all()\n\n    def get_serializer_class(self, request, view):\n        return PostSerializer\n\nclass UserRoleFilter(RoleFilter):\n    role_id = 'user'\n\n    def get_allowed_actions(self, request, view, obj=None):\n        # Users can create, list, retrieve, update their own posts\n        return ['create', 'list', 'retrieve', 'update', 'partial_update']\n\n    def get_queryset(self, request, view, queryset):\n        # Users only see their own posts\n        return queryset.filter(user=request.user)\n\n    def get_serializer_class(self, request, view):\n        return PostSerializerForUser\n\n    def get_serializer(self, request, view, serializer_class, *args, **kwargs):\n        # Example of dynamically modifying serializer fields for a user role\n        fields = ('body', 'created_at', 'id', 'title', 'updated_at')\n        return serializer_class(*args, fields=fields, **kwargs)\n\n# --- ViewSet (views.py) ---\nclass PostViewSet(RoleFilterModelViewSet):\n    queryset = Post.objects.all()\n    serializer_class = PostSerializer\n    role_filter_classes = [AdminRoleFilter, UserRoleFilter]\n\n    def get_role_id(self, request):\n        # This method is crucial: it determines the role for the current request\n        # In a real app, request.user would be an authenticated user object.\n        # For this example, we assume request.user has a 'role' attribute.\n        # You might use request.user.is_staff or custom logic here.\n        if request.user.is_authenticated:\n            return request.user.role\n        return 'anonymous' # Fallback or specific anonymous role\n\n    def perform_create(self, serializer):\n        serializer.save(user=self.request.user)\n\n# Example usage (not directly runnable without Django/DRF server):\n# from rest_framework.test import APIRequestFactory\n# from django.contrib.auth.models import AnonymousUser\n#\n# factory = APIRequestFactory()\n#\n# # Simulate an admin user\n# admin_user = User(username='admin', role='admin', is_authenticated=True)\n# request = factory.get('/posts/')\n# request.user = admin_user\n# view = PostViewSet.as_view({'get': 'list'})\n# response = view(request)\n# print(f\"Admin response status: {response.status_code}\")\n#\n# # Simulate a regular user\n# regular_user = User(username='user1', role='user', is_authenticated=True)\n# request = factory.get('/posts/')\n# request.user = regular_user\n# view = PostViewSet.as_view({'get': 'list'})\n# response = view(request)\n# print(f\"User response status: {response.status_code}\")\n\n# In a real Django setup, you would add PostViewSet to your urls.py:\n# from django.urls import path, include\n# from rest_framework.routers import DefaultRouter\n#\n# router = DefaultRouter()\n# router.register(r'posts', PostViewSet)\n#\n# urlpatterns = [\n#     path('api/', include(router.urls)),\n# ]","lang":"python","description":"This quickstart demonstrates how to define role-specific filters using `RoleFilter` subclasses and apply them to a `RoleFilterModelViewSet`. Each `RoleFilter` defines allowed actions, queryset filtering, and serializer classes based on a `role_id`. The `get_role_id` method on the `ViewSet` dynamically determines the user's role."},"warnings":[{"fix":"Upgrade Python to 3.8+, Django to 3.1+, and DRF to 3.12+ (or compatible versions as per project's dependencies).","message":"Version 1.1.0 dropped support for older Python (3.6/3.7), Django (2.2.x/3.0.x), and Django REST Framework (3.10.x/3.11.x) versions. Ensure your environment meets the new requirements.","severity":"breaking","affected_versions":">=1.1.0"},{"fix":"Update your `RoleFilterModelViewSet` (or any view using `RoleFilterMixin`) to use `role_filter_classes = [YourRoleFilter1, YourRoleFilter2]` instead of `role_filter_group = [...]`.","message":"In version 1.0.0, the `RoleFilterMixin`'s `role_filter_group` attribute was replaced by `role_filter_classes` (a list of `RoleFilter` instances).","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Carefully implement `get_role_id(self, request)` to accurately map `request.user` to one of your defined `role_id` strings (e.g., 'admin', 'user'). Ensure all possible user states (e.g., authenticated, unauthenticated, different user types) are handled.","message":"The `get_role_id` method on your `RoleFilterModelViewSet` is critical. It must return a string that matches the `role_id` defined in your `RoleFilter` subclasses. An incorrect or missing implementation will prevent the role-based filtering from activating correctly, potentially leading to unintended access or data exposure.","severity":"gotcha","affected_versions":"All"},{"fix":"Thoroughly review each `RoleFilter` class to ensure all necessary methods are implemented and return the expected restrictions or resources for that specific role. Be explicit to prevent accidental over-permissioning.","message":"Each `RoleFilter` subclass must explicitly define `get_allowed_actions`, `get_queryset`, and `get_serializer_class` (and optionally `get_serializer`) for its `role_id`. Failing to define these for a particular role might lead to default DRF behaviors (e.g., full queryset access) that bypass your intended role-based restrictions.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-12T00:00:00.000Z","next_check":"2026-07-11T00:00:00.000Z"}