diff --git a/rest_framework/viewsets.py b/rest_framework/viewsets.py index 2eba17b4a..a9c90a8d9 100644 --- a/rest_framework/viewsets.py +++ b/rest_framework/viewsets.py @@ -19,6 +19,7 @@ automatically. from functools import update_wrapper from inspect import getmembers +from django import VERSION as DJANGO_VERSION from django.urls import NoReverseMatch from django.utils.decorators import classonlymethod from django.views.decorators.csrf import csrf_exempt @@ -136,6 +137,12 @@ class ViewSetMixin: view.cls = cls view.initkwargs = initkwargs view.actions = actions + + # Exempt from Django's LoginRequiredMiddleware. Users should set + # DEFAULT_PERMISSION_CLASSES to 'rest_framework.permissions.IsAuthenticated' instead + if DJANGO_VERSION >= (5, 1): + view.login_required = False + return csrf_exempt(view) def initialize_request(self, request, *args, **kwargs): diff --git a/tests/test_viewsets.py b/tests/test_viewsets.py index 8e439c86e..68b1207c3 100644 --- a/tests/test_viewsets.py +++ b/tests/test_viewsets.py @@ -1,6 +1,8 @@ +import unittest from functools import wraps import pytest +from django import VERSION as DJANGO_VERSION from django.db import models from django.test import TestCase, override_settings from django.urls import include, path @@ -196,6 +198,11 @@ class InitializeViewSetsTestCase(TestCase): assert get.view.action == 'list_action' assert head.view.action == 'list_action' + @unittest.skipUnless(DJANGO_VERSION >= (5, 1), 'Only for Django 5.1+') + def test_login_required_middleware_compat(self): + view = ActionViewSet.as_view(actions={'get': 'list'}) + assert view.login_required is False + class GetExtraActionsTests(TestCase):