When building APIs, clients often want to control the order in which data is returned—such as sorting blog posts by date or products by price. Django Rest Framework provides a built-in tool for this: OrderingFilter
.
This article covers:
-
What
OrderingFilter
is -
How it works
-
Step-by-step setup
-
Full working example
-
Tips and best practices
-
Common pitfalls
What is OrderingFilter
?
OrderingFilter
is a filter backend in DRF that allows API consumers to sort query results dynamically using a query parameter (usually ?ordering=
).
It supports:
-
Ascending (
?ordering=price
) -
Descending (
?ordering=-price
) -
Multi-field ordering (
?ordering=price,-name
)
It’s part of the DRF core, so no third-party installation is required.
⚙️ How Does It Work?
You must:
-
Add
OrderingFilter
tofilter_backends
in your view or globally. -
Define which fields can be used for ordering with
ordering_fields
. -
Optionally, define a
default_ordering
.
Step-by-Step: Implementing OrderingFilter
Step 1: Import and Configure
from rest_framework.filters import OrderingFilter
Step 2: Use It in Your View or ViewSet
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework.filters import OrderingFilter
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = [OrderingFilter]
ordering_fields = ['price', 'created_at', 'name'] # Allow sorting by these fields
ordering = ['-created_at'] # Default order if none is specified
Step 3: Use in API Request
Examples:
-
Ascending:
GET /api/products/?ordering=price
-
Descending:
GET /api/products/?ordering=-price
-
Multiple fields:
GET /api/products/?ordering=price,-name
✅ Full Working Example
models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)
serializers.py
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
views.py
from rest_framework import viewsets
from rest_framework.filters import OrderingFilter
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = [OrderingFilter]
ordering_fields = ['price', 'name', 'created_at']
ordering = ['-created_at']
urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet
router = DefaultRouter()
router.register('products', ProductViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]
Tips and Best Practices
Tip | Why It Helps |
---|---|
✅ Always define ordering_fields |
Prevents users from ordering by unintended fields |
✅ Use indexes on fields used for ordering | Speeds up database queries |
✅ Set ordering for predictable defaults |
Improves UX when no param is passed |
✅ Combine with SearchFilter or DjangoFilterBackend |
Adds more flexibility to your API |
⚠️ Common Pitfalls
Pitfall | Fix |
---|---|
❌ Ordering doesn't work | Ensure OrderingFilter is in filter_backends |
❌ Unexpected fields exposed | Use ordering_fields to limit them |
❌ Large queries are slow | Add database indexes on sortable fields |
❌ Using ordering without defined fields |
May expose sensitive data fields unintentionally |
Combine with Other Filters
You can mix OrderingFilter
with:
-
SearchFilter
-
DjangoFilterBackend
-
Custom filter backends
filter_backends = [SearchFilter, OrderingFilter, DjangoFilterBackend]
Conclusion
OrderingFilter
is a simple yet powerful feature in Django Rest Framework that lets you expose dynamic sorting to your API consumers. Whether you're building product catalogs, blog feeds, or sortable dashboards, it's an essential tool for a better frontend experience.