Django REST Framework mixins for ViewSets and APIViews - APIMixin, ModelMixin, RelationshipFilterMixin, RoleBasedFilterMixin. Simplify Django API development with reusable mixins.
Project description
django-api-mixins
Django REST Framework API Mixins - A collection of powerful, reusable mixins for Django REST Framework ViewSets and APIViews to simplify common API development patterns. Perfect for building REST APIs with Django.
📦 Available on PyPI: https://pypi.org/project/django-api-mixins/
Keywords: Django REST Framework, DRF, Django API, ViewSets, APIViews, Mixins, Django Mixins, REST API, Serializers, Queryset Filtering
Features
- APIMixin: Dynamic serializer selection based on action (create, update, list, retrieve)
- ModelMixin: Automatic filter field generation for Django models
- ModelFilterFieldsMixin: Automatically sets
filterset_fieldsfrom models withget_filter_fields()(requiresdjango-filter) - OpenAPIFilterParametersMixin: Adds OpenAPI/Swagger filter parameters for APIView (requires
django-filteranddrf-spectacular) - RelationshipFilterMixin: Automatic filtering for reverse relationships and direct fields
- RoleBasedFilterMixin: Role-based queryset filtering for multi-tenant applications
Installation
Basic installation:
pip install django-api-mixins
With optional dependencies:
# For ModelFilterFieldsMixin (requires django-filter)
pip install django-api-mixins[filters]
# For OpenAPIFilterParametersMixin (requires drf-spectacular)
pip install django-api-mixins[spectacular]
# Install all optional dependencies
pip install django-api-mixins[all]
Requirements
Core dependencies (required):
- Python 3.8+
- Django 3.2+
- Django REST Framework 3.12+
Optional dependencies:
django-filter>=23.0- Required forModelFilterFieldsMixinandOpenAPIFilterParametersMixindrf-spectacular>=0.26.0- Required forOpenAPIFilterParametersMixin
Quick Start
APIMixin
Use different serializers for different actions (create, update, list, retrieve):
from rest_framework import viewsets
from django_api_mixins import APIMixin
class UserViewSet(APIMixin, viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer # Default serializer
create_serializer_class = UserCreateSerializer # For POST requests
update_serializer_class = UserUpdateSerializer # For PUT/PATCH requests
list_serializer_class = UserListSerializer # For GET list requests
retrieve_serializer_class = UserDetailSerializer # For GET detail requests
The mixin also automatically handles list data in requests:
# POST /api/users/
# Body: [{"name": "User1"}, {"name": "User2"}]
# Automatically sets many=True for list data
ModelMixin
Automatically generate filter fields for all model fields:
from django.db import models
from django_api_mixins import ModelMixin
class Product(models.Model, ModelMixin):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
# Automatically generates filter fields:
# - name: exact, in, isnull
# - price: exact, in, isnull, gte, lte
# - created_at: exact, in, isnull, gte, lte
# - is_active: exact, in, isnull
Use in your ViewSet with Django Filter Backend:
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from django_api_mixins import ModelMixin
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = Product.get_filter_fields() # Use auto-generated fields
Filter related models:
# Get filter fields for a related model
filter_fields = Product.get_filter_fields_for_related_model('category')
# Returns: {'category__name': [...], 'category__id': [...], ...}
# Get filter fields for a foreign key field
filter_fields = Order.get_filter_fields_for_foreign_fields('product')
# Returns: {'product__name': [...], 'product__price': [...], ...}
ModelFilterFieldsMixin
⚠️ Requires: django-filter package. Install with pip install django-filter or pip install django-api-mixins[filters]
Automatically sets filterset_fields from a model that uses ModelMixin (or any model with a get_filter_fields() class method). Works with APIView, GenericAPIView, and ViewSets.
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from django_api_mixins import ModelFilterFieldsMixin
# ViewSet / GenericAPIView: filter fields come from queryset.model
class UnitViewSet(ModelFilterFieldsMixin, viewsets.ModelViewSet):
queryset = Unit.objects.all() # Unit must have ModelMixin or get_filter_fields()
serializer_class = UnitSerializer
filter_backends = [DjangoFilterBackend]
# filterset_fields auto-set from Unit.get_filter_fields()
# APIView: set model so the mixin can resolve filter fields
from rest_framework.views import APIView
class UnitListAPIView(ModelFilterFieldsMixin, APIView):
model = Unit # required for APIView
filter_backends = [DjangoFilterBackend]
def get_queryset(self):
return Unit.objects.all()
def get(self, request):
queryset = self.filter_queryset(self.get_queryset())
# ... rest of your logic
# Optional: use a different model for filter fields than the queryset model
class MyViewSet(ModelFilterFieldsMixin, viewsets.ModelViewSet):
queryset = SomeProxy.objects.all()
filterset_model = Unit # use Unit.get_filter_fields() instead of SomeProxy
filter_backends = [DjangoFilterBackend]
Note: If django-filter is not installed, you'll get a clear error message with installation instructions when you try to use this mixin.
OpenAPIFilterParametersMixin
⚠️ Requires: Both django-filter and drf-spectacular packages. Install with pip install django-filter drf-spectacular or pip install django-api-mixins[all]
Adds OpenAPI/Swagger filter parameters for plain APIView so Swagger shows the same filter query params as GenericAPIView/ViewSet. For GenericAPIView/ViewSet this mixin is a no-op (Spectacular already adds params).
from rest_framework.views import APIView
from django_filters.rest_framework import DjangoFilterBackend
from django_api_mixins import OpenAPIFilterParametersMixin, ModelFilterFieldsMixin
# With Swagger/OpenAPI filter parameters
class UnitListAPIView(OpenAPIFilterParametersMixin, ModelFilterFieldsMixin, APIView):
model = Unit # required
filter_backends = [DjangoFilterBackend]
def get_queryset(self):
return Unit.objects.all()
def get(self, request):
queryset = self.filter_queryset(self.get_queryset())
# ... rest of your logic
# Filter parameters will appear in Swagger/OpenAPI docs
# Without Swagger params: use only ModelFilterFieldsMixin
class UnitListAPIView(ModelFilterFieldsMixin, APIView):
model = Unit
filter_backends = [DjangoFilterBackend]
# Filtering works, but params won't appear in OpenAPI docs
Note: If django-filter or drf-spectacular is not installed, you'll get a clear error message with installation instructions when you try to use this mixin.
RelationshipFilterMixin
Automatically apply filters for reverse relationships and direct fields:
from rest_framework import viewsets
from django_api_mixins import RelationshipFilterMixin
class OrderViewSet(RelationshipFilterMixin, viewsets.ModelViewSet):
queryset = Order.objects.all()
# Define which reverse relationship filters to allow
reverse_relation_filters = [
'customer__name',
'customer__email',
'product__category__name',
]
# Define which filters support list/array values
listable_filters = ['customer__id', 'product__id']
Important: Place the mixin BEFORE the ViewSet class:
# ✅ Correct
class OrderViewSet(RelationshipFilterMixin, viewsets.ModelViewSet):
pass
# ❌ Wrong
class OrderViewSet(viewsets.ModelViewSet, RelationshipFilterMixin):
pass
Usage examples:
# Filter by customer name
GET /api/orders/?customer__name=John
# Filter by multiple customer IDs (listable filter)
GET /api/orders/?customer__id=1,2,3
# or
GET /api/orders/?customer__id=[1,2,3]
# Filter by product category
GET /api/orders/?product__category__name=Electronics
RoleBasedFilterMixin
Automatically filter querysets based on user roles:
from rest_framework import viewsets
from django_api_mixins import RoleBasedFilterMixin
class OrderViewSet(RoleBasedFilterMixin, viewsets.ModelViewSet):
queryset = Order.objects.all()
# Required: field name to filter on
role_filter_field = 'operator_type'
# Optional: roles that see all data
admin_roles = ['admin', 'super_admin']
# Optional: roles that see no data
excluded_roles = ['guest']
# Optional: custom role to field value mapping
role_mapping = {
'custom_role': 'custom_value',
'manager': 'MGR',
}
Important: Place the mixin BEFORE the ViewSet class:
# ✅ Correct
class OrderViewSet(RoleBasedFilterMixin, viewsets.ModelViewSet):
pass
# ❌ Wrong
class OrderViewSet(viewsets.ModelViewSet, RoleBasedFilterMixin):
pass
How it works:
- Extracts the user's role from
user.role.name - Admin roles see all data (no filtering)
- Excluded roles see no data (empty queryset)
- Other roles are filtered by
role_filter_field = role_name(or mapped value)
Example:
# User with role.name = 'operator'
# Model has operator_type field
# Automatically filters: Order.objects.filter(operator_type='operator')
# User with role.name = 'admin'
# Sees all orders (no filtering)
# User with role.name = 'guest'
# Sees no orders (queryset.none())
FieldLookup Enum
The package includes a FieldLookup enum for consistent lookup naming:
from django_api_mixins import FieldLookup
FieldLookup.EXACT # "exact"
FieldLookup.ICONTAINS # "icontains"
FieldLookup.CONTAINS # "contains"
FieldLookup.ISNULL # "isnull"
FieldLookup.GTE # "gte"
FieldLookup.LTE # "lte"
FieldLookup.IN # "in"
Combining Mixins
You can combine multiple mixins:
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from django_api_mixins import (
APIMixin,
ModelFilterFieldsMixin,
RelationshipFilterMixin,
RoleBasedFilterMixin,
)
class OrderViewSet(
ModelFilterFieldsMixin, # Auto-set filterset_fields from model
RelationshipFilterMixin,
RoleBasedFilterMixin,
APIMixin,
viewsets.ModelViewSet
):
queryset = Order.objects.all()
serializer_class = OrderSerializer
create_serializer_class = OrderCreateSerializer
filter_backends = [DjangoFilterBackend]
role_filter_field = 'operator_type'
reverse_relation_filters = ['customer__name', 'product__category__name']
listable_filters = ['customer__id']
Note: The order of mixins matters! Place filtering mixins before the ViewSet class.
Optional Dependencies: If using ModelFilterFieldsMixin or OpenAPIFilterParametersMixin, make sure to install the required dependencies:
ModelFilterFieldsMixinrequires:django-filterOpenAPIFilterParametersMixinrequires:django-filteranddrf-spectacular
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE file for details.
Support
For issues, questions, or contributions, please visit the GitHub repository.
PyPI
This package is published on PyPI and can be installed via pip:
pip install django-api-mixins
PyPI Project Page: https://pypi.org/project/django-api-mixins/
Latest Version: 0.1.2 (Released: Feb 21, 2026)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_api_mixins-0.1.2.tar.gz.
File metadata
- Download URL: django_api_mixins-0.1.2.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e94b88464eec177e455d1caef355c2a317529741861156fe4cb24e95c4955ca
|
|
| MD5 |
b745fc6e42791ad4391e24121a29eb20
|
|
| BLAKE2b-256 |
2c1f2a96c1770f4edead3786fbadf051346a6a66f8070e90110ac1712a05f298
|
File details
Details for the file django_api_mixins-0.1.2-py3-none-any.whl.
File metadata
- Download URL: django_api_mixins-0.1.2-py3-none-any.whl
- Upload date:
- Size: 12.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a73d75ad2b22ee18b01700c4f8a51e1f5ed6f80ac7103f54641c8696fed9e80
|
|
| MD5 |
98a72416087e58379ef74884552e05ac
|
|
| BLAKE2b-256 |
e705467a8c1ff26fc31606a0f475306049b079d9932ae1b3647a7a36f00e4daa
|