This commit is contained in:
Cheery 2025-08-10 12:58:54 +01:00 committed by GitHub
commit fa86b8f8bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 72 additions and 2 deletions

View File

@ -70,6 +70,15 @@ def api_view(http_method_names=None):
WrappedAPIView.permission_classes = getattr(func, 'permission_classes',
APIView.permission_classes)
WrappedAPIView.content_negotiation_class = getattr(func, 'content_negotiation_class',
APIView.content_negotiation_class)
WrappedAPIView.metadata_class = getattr(func, 'metadata_class',
APIView.metadata_class)
WrappedAPIView.versioning_class = getattr(func, "versioning_class",
APIView.versioning_class)
WrappedAPIView.schema = getattr(func, 'schema',
APIView.schema)
@ -113,6 +122,27 @@ def permission_classes(permission_classes):
return decorator
def content_negotiation_class(content_negotiation_class):
def decorator(func):
func.content_negotiation_class = content_negotiation_class
return func
return decorator
def metadata_class(metadata_class):
def decorator(func):
func.metadata_class = metadata_class
return func
return decorator
def versioning_class(versioning_class):
def decorator(func):
func.versioning_class = versioning_class
return func
return decorator
def schema(view_inspector):
def decorator(func):
func.schema = view_inspector

View File

@ -6,9 +6,11 @@ from django.test import TestCase
from rest_framework import status
from rest_framework.authentication import BasicAuthentication
from rest_framework.decorators import (
action, api_view, authentication_classes, parser_classes,
permission_classes, renderer_classes, schema, throttle_classes
action, api_view, authentication_classes, content_negotiation_class,
metadata_class, parser_classes, permission_classes, renderer_classes,
schema, throttle_classes, versioning_class
)
from rest_framework.negotiation import BaseContentNegotiation
from rest_framework.parsers import JSONParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import JSONRenderer
@ -16,6 +18,7 @@ from rest_framework.response import Response
from rest_framework.schemas import AutoSchema
from rest_framework.test import APIRequestFactory
from rest_framework.throttling import UserRateThrottle
from rest_framework.versioning import QueryParameterVersioning
from rest_framework.views import APIView
@ -150,6 +153,43 @@ class DecoratorTestCase(TestCase):
response = view(request)
assert response.status_code == status.HTTP_429_TOO_MANY_REQUESTS
def test_versioning_class(self):
@api_view(["GET"])
@versioning_class(QueryParameterVersioning)
def view(request):
return Response({"version": request.version})
request = self.factory.get("/?version=1.2.3")
response = view(request)
assert response.data == {"version": "1.2.3"}
def test_metadata_class(self):
# From TestMetadata.test_none_metadata()
@api_view()
@metadata_class(None)
def view(request):
return Response({})
request = self.factory.options('/')
response = view(request)
assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
assert response.data == {'detail': 'Method "OPTIONS" not allowed.'}
def test_content_negotiation(self):
class CustomContentNegotiation(BaseContentNegotiation):
def select_renderer(self, request, renderers, format_suffix):
assert request.META['HTTP_ACCEPT'] == 'custom/type'
return (renderers[0], renderers[0].media_type)
@api_view(["GET"])
@content_negotiation_class(CustomContentNegotiation)
def view(request):
return Response({})
request = self.factory.get('/', HTTP_ACCEPT='custom/type')
response = view(request)
assert response.status_code == status.HTTP_200_OK
def test_schema(self):
"""
Checks CustomSchema class is set on view