A collection of useful mixins for Django REST Framework ViewSets and APIViews
Project description
django-api-mixins
A collection of useful mixins for Django REST Framework ViewSets and APIViews to simplify common API patterns.
Features
- APIMixin: Dynamic serializer selection based on action (create, update, list, retrieve)
- ModelMixin: Automatic filter field generation for Django models
- RelationshipFilterMixin: Automatic filtering for reverse relationships and direct fields
- RoleBasedFilterMixin: Role-based queryset filtering for multi-tenant applications
Installation
pip install django-api-mixins
Requirements
- Python 3.8+
- Django 3.2+
- Django REST Framework 3.12+
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': [...], ...}
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_api_mixins import (
APIMixin,
RelationshipFilterMixin,
RoleBasedFilterMixin,
)
class OrderViewSet(
RelationshipFilterMixin,
RoleBasedFilterMixin,
APIMixin,
viewsets.ModelViewSet
):
queryset = Order.objects.all()
serializer_class = OrderSerializer
create_serializer_class = OrderCreateSerializer
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.
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.
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.0.tar.gz.
File metadata
- Download URL: django_api_mixins-0.1.0.tar.gz
- Upload date:
- Size: 8.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fbdf5cdfa529a1162b56298e151d6d05f113c9a93626360ffb353b3bf5ed9e61
|
|
| MD5 |
5c28f0b1b5f5ddaec25f7255bbd112bc
|
|
| BLAKE2b-256 |
3fbb63264cf62005cf33a87bf127ff97edcce5b62acef9b33bdab5869886a721
|
File details
Details for the file django_api_mixins-0.1.0-py3-none-any.whl.
File metadata
- Download URL: django_api_mixins-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.6 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 |
9e3a9884fde9d1429001f92a65e89d581765443389e03393a3601ccfd6de6198
|
|
| MD5 |
d7c79423edb5d6d31e839dec4ec69adc
|
|
| BLAKE2b-256 |
e36e4fb689607d93eef5c0ba480051c324dc6fe01a38ebbabe487f0725a98b19
|