edX DRF Extensions
edX DRF Extensions provides a collection of utility classes, authenticators, permissions, and exception handlers designed to extend Django REST Framework for use within the Open edX ecosystem. It is currently at version 10.6.0, with a frequent release cadence tied to Django and Python version compatibility and Open edX platform development.
Common errors
-
ModuleNotFoundError: No module named 'edx_drf_extensions.utils.exception_handler'
cause The `exception_handler` was moved directly into the top-level `edx_drf_extensions` package.fixUpdate your import statement to `from edx_drf_extensions.exception_handler import exception_handler` and adjust your `REST_FRAMEWORK` settings accordingly. -
TypeError: JwtAuthenticationError.__init__() takes 1 positional argument but 2 were given
cause In version 10.2.0, the base class for `JwtAuthenticationError` was changed, potentially altering its constructor signature or expected arguments.fixIf you're raising `JwtAuthenticationError` directly, ensure you're calling it with the correct arguments as expected by the version you're using. If you have custom error handling, review how this exception is caught and handled. -
django.core.exceptions.ImproperlyConfigured: 'edx_drf_extensions' must be in INSTALLED_APPS to use 'edx_drf_extensions.auth.jwt.authentication.JwtCookieAuthentication'
cause The `edx-drf-extensions` package itself needs to be registered with Django.fixAdd `'edx_drf_extensions'` to your `INSTALLED_APPS` list in your Django `settings.py` file.
Warnings
- breaking Python 3.8 support was dropped in version 10.4.0. Projects using older Python versions must upgrade their environment or stick to `edx-drf-extensions < 10.4.0`.
- breaking The behavior of JWT authentication changed significantly in v10.0.0, making 'forgiving JWTs' the default. This means JWTs that fail verification due to expiry or other issues might be silently ignored if another authentication method succeeds, which could alter security assumptions.
- gotcha There were several changes, reverts, and fixes related to JWT vs session user checks around versions 9.1.0-9.1.2. Upgrading between these minor versions, or to/from 10.0.0, could lead to unexpected authentication behavior or regressions.
- gotcha Version 10.6.0 added support for Django 5.2. If you are using an older version of `edx-drf-extensions` with Django 5.x, you may encounter compatibility issues or `DeprecationWarnings` from Django. Older `edx-drf-extensions` versions are not guaranteed to support newer Django releases.
Install
-
pip install edx-drf-extensions
Imports
- JwtCookieAuthentication
from edx_drf_extensions.auth.jwt.authentication import JwtCookieAuthentication
- exception_handler
from edx_drf_extensions.utils.exception_handler import exception_handler
from edx_drf_extensions.exception_handler import exception_handler
- DefaultPagination
from edx_drf_extensions.pagination import DefaultPagination
- ReadOnlyAuditMixin
from edx_drf_extensions.mixins import ReadOnlyAuditMixin
- JwtAuthenticationError
from edx_drf_extensions.auth.jwt.errors import JwtAuthenticationError
Quickstart
import os
from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.decorators import action
from django.http import Http404
# Ensure these imports are correct for your installed version
from edx_drf_extensions.auth.jwt.authentication import JwtCookieAuthentication
from edx_drf_extensions.exception_handler import exception_handler
# In a Django settings.py file, you'd typically configure DRF:
# REST_FRAMEWORK = {
# 'DEFAULT_AUTHENTICATION_CLASSES': [
# 'edx_drf_extensions.auth.jwt.authentication.JwtCookieAuthentication',
# 'rest_framework.authentication.SessionAuthentication',
# ],
# 'EXCEPTION_HANDLER': 'edx_drf_extensions.exception_handler.exception_handler'
# }
class MyTestViewSet(viewsets.ViewSet):
"""A simple DRF view demonstrating edx-drf-extensions authentication."""
authentication_classes = [JwtCookieAuthentication]
# Permission classes would typically be added here, e.g., IsAuthenticated
def list(self, request):
if request.user.is_authenticated:
return Response({"message": f"Hello {request.user.username}, authenticated via JWT!"}, status=status.HTTP_200_OK)
return Response({"message": "Authentication failed."},
status=status.HTTP_401_UNAUTHORIZED)
@action(detail=False, methods=['get'])
def cause_handled_error(self, request):
"""Endpoint to demonstrate the custom exception handler."""
# This error will be caught by DRF's exception handling, if configured.
raise Http404("The requested resource was not found. (Handled by edx-drf-extensions)")
print("Quickstart code demonstrates applying JwtCookieAuthentication to a DRF ViewSet.")
print("It also hints at configuring the custom exception_handler in settings.py.")
print("To run fully, integrate into a Django/DRF project and configure REST_FRAMEWORK.")