Django REST Framework: Paging
For list endpoints, LDAP ORM provides integration with Django REST Framework (DRF) through specialized pagination support that work with LDAP ORM models and fields.
LdapCursorPagination: Server-side LDAP paging for efficient handling of large result sets
LDAP Paging
LDAP ORM provides server-side paging through LdapCursorPagination, which
uses LDAP’s SimplePagedResultsControl for efficient handling of large result
sets.
Why Use LDAP Paging?
Prevents timeouts: Large LDAP queries can cause client or server timeouts
Memory efficiency: Avoids loading entire result sets into memory
Server-side processing: Leverages LDAP server’s native paging capabilities
Unindexed attributes: Efficient for queries on unindexed attributes
Scalability: Handles result sets of any size
LdapCursorPagination
The LdapCursorPagination class provides cursor-based pagination using
base64-encoded LDAP cookies:
from ldaporm.restframework import LdapCursorPagination
class MyLdapCursorPagination(LdapCursorPagination):
page_size = 100 # Default page size
page_size_query_param = 'page_size' # Query parameter for page size
max_page_size = 1000 # Maximum allowed page size
cursor_query_param = 'next_token' # Query parameter for next page cursor
Basic Usage
from rest_framework import viewsets
from ldaporm.restframework import LdapCursorPagination
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
pagination_class = LdapCursorPagination
lookup_field = 'dn'
def get_queryset(self):
return User.objects.all()
Global Configuration
You can configure LDAP paging globally in your Django settings:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'ldaporm.restframework.LdapCursorPagination',
'PAGE_SIZE': 100,
}
API Response Format
{
"results": [
{
"url": "http://example.com/api/users/cn=john.doe,ou=users,dc=example,dc=com/",
"username": "john.doe",
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.com",
"is_active": true,
"dn": "cn=john.doe,ou=users,dc=example,dc=com"
},
{
"url": "http://example.com/api/users/cn=jane.smith,ou=users,dc=example,dc=com/",
"username": "jane.smith",
"first_name": "Jane",
"last_name": "Smith",
"email": "jane.smith@example.com",
"is_active": true,
"dn": "cn=jane.smith,ou=users,dc=example,dc=com"
}
],
"has_more": true,
"next": "http://example.com/api/users/?next_token=dGVzdF9jb29raWVfMTIz"
}
Query Parameters
page_size: Number of results per page (default: 100, max: 1000)next_token: Base64-encoded cursor for the next page. You don’t need to pass this parameter on the first page.
Note
The page_size parameter is automatically preserved in the next URL,
ensuring that subsequent pages maintain the same page size requested by the
user.
Example Requests
# First page
GET /api/users/
# Next page
GET /api/users/?next_token=dGVzdF9jb29raWVfMTIz
# Custom page size
GET /api/users/?page_size=50
# Next page with custom size
GET /api/users/?page_size=50&next_token=dGVzdF9jb29raWVfMTIz
Paging with Filters
LDAP paging works seamlessly with filters and other query parameters:
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
pagination_class = LdapCursorPagination
lookup_field = 'dn'
def get_queryset(self):
queryset = User.objects.all()
# Apply filters
is_active = self.request.query_params.get('is_active')
if is_active is not None:
queryset = queryset.filter(is_active=is_active.lower() == 'true')
return queryset
# Filtered and paged request
GET /api/users/?is_active=true&page_size=25
# Next page of filtered results
GET /api/users/?is_active=true&page_size=25&next_token=dGVzdF9jb29raWVfMTIz
Best Practices
Always use paging: Configure paging for all list endpoints
Set reasonable page sizes: Default to 100, allow up to 1000
Handle cursor errors: Invalid cursors should start from the beginning
Preserve query parameters: The pagination automatically preserves all query parameters (including
page_size, filters, etc.) in the next page URLTest with large datasets: Ensure paging works with your expected data volumes