1+ """OpenAPI core contrib django decorators module"""
2+ from typing import Type
3+
4+ from django .conf import settings
5+ from django .http .request import HttpRequest
6+ from django .http .response import HttpResponse
7+
8+ from jsonschema_path import SchemaPath
9+
10+ from openapi_core import OpenAPI
11+ from openapi_core .contrib .django .integrations import DjangoIntegration
12+ from openapi_core .contrib .django .requests import DjangoOpenAPIRequest
13+ from openapi_core .contrib .django .responses import DjangoOpenAPIResponse
14+ from openapi_core .contrib .django .handlers import DjangoOpenAPIErrorsHandler
15+ from openapi_core .contrib .django .handlers import (
16+ DjangoOpenAPIValidRequestHandler ,
17+ )
18+
19+ class DjangoOpenAPIDecorator (DjangoIntegration ):
20+ valid_request_handler_cls = DjangoOpenAPIValidRequestHandler
21+ errors_handler_cls : Type [DjangoOpenAPIErrorsHandler ] = DjangoOpenAPIErrorsHandler
22+
23+ def __init__ (
24+ self ,
25+ openapi : OpenAPI == None ,
26+ request_cls : Type [DjangoOpenAPIRequest ] = DjangoOpenAPIRequest ,
27+ response_cls : Type [DjangoOpenAPIResponse ] = DjangoOpenAPIResponse ,
28+ errors_handler_cls : Type [
29+ DjangoOpenAPIErrorsHandler
30+ ] = DjangoOpenAPIErrorsHandler
31+ ):
32+ if openapi is None :
33+ openapi = get_default_openapi_instance ()
34+
35+ super ().__init__ (openapi )
36+
37+ # If OPENAPI_RESPONSE_CLS is defined in settings.py (for custom response classes),
38+ # set the response_cls accordingly.
39+ if hasattr (settings , "OPENAPI_RESPONSE_CLS" ):
40+ response_cls = settings .OPENAPI_RESPONSE_CLS
41+
42+ self .request_cls = request_cls
43+ self .response_cls = response_cls
44+
45+ def __call__ (self , view_func ):
46+ """
47+ Thanks to this method, the class acts as a decorator.
48+ Example usage:
49+
50+ @DjangoOpenAPIDecorator()
51+ def my_view(request): ...
52+
53+ """
54+
55+ def _wrapped_view (request : HttpRequest , * args , ** kwargs ) -> HttpResponse :
56+ # get_response is the function that we treats
57+ # as the "next step" in the chain (i.e., our original view).
58+ def get_response (r : HttpRequest ) -> HttpResponse :
59+ return view_func (r , * args , ** kwargs )
60+
61+ # Create a handler that will validate the request.
62+ valid_request_handler = self .valid_request_handler_cls (request , get_response )
63+
64+ # Validate the request (before running the view).
65+ errors_handler = self .errors_handler_cls ()
66+ response = self .handle_request (request , valid_request_handler , errors_handler )
67+
68+ # Validate the response (after the view) if should_validate_response() returns True.
69+ return self .handle_response (request , response , errors_handler )
70+
71+ return _wrapped_view
72+
73+ @classmethod
74+ def from_spec (
75+ cls ,
76+ spec : SchemaPath ,
77+ request_cls : Type [DjangoOpenAPIRequest ] = DjangoOpenAPIRequest ,
78+ response_cls : Type [DjangoOpenAPIResponse ] = DjangoOpenAPIResponse ,
79+ errors_handler_cls : Type [
80+ DjangoOpenAPIErrorsHandler
81+ ] = DjangoOpenAPIErrorsHandler ,
82+ ) -> "DjangoOpenAPIViewDecorator" :
83+ openapi = OpenAPI (spec )
84+ return cls (
85+ openapi ,
86+ request_cls = request_cls ,
87+ response_cls = response_cls ,
88+ errors_handler_cls = errors_handler_cls ,
89+ )
0 commit comments