{"id":3982,"library":"drf-extensions","title":"DRF-extensions","description":"DRF-extensions is a collection of custom extensions for Django REST Framework, designed to enhance API functionality and performance. It provides features like response caching, conditional requests, nested routes, and bulk operations. The library is actively maintained, with version 0.8.0 released recently, and it follows a regular release cadence to support newer Django and DRF versions.","status":"active","version":"0.8.0","language":"en","source_language":"en","source_url":"https://github.com/chibisov/drf-extensions","tags":["django","drf","rest-framework","api","extensions","caching","throttling","bulk-operations","nested-routes"],"install":[{"cmd":"pip install drf-extensions","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core dependency; this library extends DRF.","package":"djangorestframework","optional":false},{"reason":"Core dependency; DRF itself depends on Django.","package":"django","optional":false},{"reason":"Required for some filtering functionalities.","package":"django-filter","optional":true}],"imports":[{"symbol":"cache_response","correct":"from rest_framework_extensions.cache.decorators import cache_response"},{"symbol":"DetailSerializerMixin","correct":"from rest_framework_extensions.mixins import DetailSerializerMixin"},{"symbol":"PaginateByMaxMixin","correct":"from rest_framework_extensions.mixins import PaginateByMaxMixin"},{"symbol":"ListUpdateModelMixin","correct":"from rest_framework_extensions.bulk_operations.mixins import ListUpdateModelMixin"},{"symbol":"ListDestroyModelMixin","correct":"from rest_framework_extensions.bulk_operations.mixins import ListDestroyModelMixin"},{"symbol":"NestedRouter","correct":"from rest_framework_extensions.routers import NestedRouter"},{"note":"Settings should be accessed via the extensions_api_settings object, not directly from the settings module.","wrong":"from rest_framework_extensions import settings","symbol":"extensions_api_settings","correct":"from rest_framework_extensions.settings import extensions_api_settings"}],"quickstart":{"code":"import os\nfrom django.db import models\nfrom rest_framework import views, serializers, status\nfrom rest_framework.response import Response\nfrom rest_framework_extensions.cache.decorators import cache_response\n\n# --- Minimal Django setup for demonstration (not for real project) ---\nos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')\nimport django\nif not django.apps.apps.ready:\n    django.setup()\n\n# --- Models (if needed) ---\nclass City(models.Model):\n    name = models.CharField(max_length=100)\n    population = models.IntegerField()\n\n    class Meta:\n        app_label = 'myapp' # Required for minimal setup\n\n    def __str__(self):\n        return self.name\n\n# --- Serializers (if needed) ---\nclass CitySerializer(serializers.ModelSerializer):\n    class Meta:\n        model = City\n        fields = '__all__'\n\n# --- View demonstrating caching ---\nclass CityListView(views.APIView):\n    @cache_response(timeout=60 * 15)  # Cache for 15 minutes\n    def get(self, request, *args, **kwargs):\n        # In a real app, you'd fetch from DB:\n        # cities = City.objects.all()\n        # serializer = CitySerializer(cities, many=True)\n        # For quickstart, simulate data:\n        data = [\n            {\"name\": \"New York\", \"population\": 8000000},\n            {\"name\": \"Los Angeles\", \"population\": 4000000}\n        ]\n        return Response(data, status=status.HTTP_200_OK)\n\n# --- Example of running the view (simplified) ---\n# In a real Django/DRF project, this would be part of urls.py\n# and accessible via an HTTP request.\n# For demonstration, we can simulate calling the method:\nif __name__ == '__main__':\n    # This part would typically be handled by Django's URL routing\n    # and request/response cycle.\n    # For direct execution, we're just showing the decorator effect conceptualy.\n    print(\"Simulating API call with caching...\")\n    view = CityListView()\n    \n    # Simulate a request object minimally for the decorator\n    class MockRequest:\n        method = 'GET'\n        path = '/cities/'\n        query_params = {}\n        # Add other attributes that might be accessed by key constructors if needed\n\n    mock_request = MockRequest()\n    response1 = view.get(mock_request)\n    print(f\"First call: {response1.data}\")\n\n    # A second call within the cache timeout period would ideally return cached data\n    # (though simulating the actual cache hit without a full Django setup is complex).\n    # The key takeaway is the decorator's placement.\n    response2 = view.get(mock_request)\n    print(f\"Second call: {response2.data}\")\n","lang":"python","description":"This quickstart demonstrates the `cache_response` decorator, a core feature of drf-extensions for improving API performance by caching viewset responses. Apply `@cache_response` directly to `APIView` methods to enable caching. Remember to configure Django's caching backend in your `settings.py` for production use."},"warnings":[{"fix":"Upgrade Django to 2.2+ and Django REST Framework to 3.12+ (or 3.9+ for versions before 0.7.0) before upgrading `drf-extensions`. Refer to the project's README for precise version compatibility.","message":"Version 0.7.0 of `drf-extensions` dropped support for Django versions below 2.2 and earlier DRF versions (specifically requiring DRF 3.9+ for 0.5.0 and DRF 3.12+ for 0.7.0). Ensure your Django and Django REST Framework versions meet the requirements when upgrading `drf-extensions` to avoid compatibility issues.","severity":"breaking","affected_versions":"0.7.0+"},{"fix":"Be aware of this behavior and implement any necessary pre/post-operation logic outside of the standard DRF/Django hooks when using bulk operations, or choose a different approach if those hooks are critical.","message":"When using bulk operations (e.g., via `ListUpdateModelMixin`, `ListDestroyModelMixin`), `drf-extensions` applies changes directly to the `QuerySet`. This bypasses standard DRF serializer `save()`/`delete()` methods, viewset lifecycle hooks (`pre_save`, `post_save`, `pre_delete`, `post_delete`), and Django model signals. Any custom logic implemented in these areas will NOT be executed during bulk operations.","severity":"gotcha","affected_versions":"All"},{"fix":"Always include the `X-BULK-OPERATION` header in requests for bulk update or delete actions, for example: `X-BULK-OPERATION: true`.","message":"For safety and to prevent accidental mass changes, `drf-extensions` bulk destroy and bulk update operations explicitly require the `X-BULK-OPERATION` header to be present in the request. If this header is missing, the API will return a `400 BAD REQUEST` error.","severity":"gotcha","affected_versions":"All"},{"fix":"For production deployments, configure Django to use a robust caching backend such as Redis (`django-redis`) or Memcached in your `settings.py` to ensure consistent and scalable caching.","message":"While `drf-extensions` provides powerful caching decorators like `@cache_response`, the underlying caching mechanism relies on Django's cache framework. The default `LocMemCache` backend in Django is not suitable for production, especially in multi-process or distributed environments, as cache entries are local to each process.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}