-
Notifications
You must be signed in to change notification settings - Fork 433
/
views.py
157 lines (132 loc) · 6.97 KB
/
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import warnings
from functools import WRAPPER_ASSIGNMENTS, wraps
from django.utils.cache import add_never_cache_headers
from django.views.decorators.cache import cache_page
from django.views.decorators.vary import vary_on_headers
from rest_framework import exceptions
from rest_framework.response import Response
from rest_framework.settings import api_settings
from rest_framework.views import APIView
from .app_settings import swagger_settings
from .renderers import (
OpenAPIRenderer, ReDocOldRenderer, ReDocRenderer, SwaggerJSONRenderer, SwaggerUIRenderer, SwaggerYAMLRenderer,
_SpecRenderer
)
SPEC_RENDERERS = (SwaggerYAMLRenderer, SwaggerJSONRenderer, OpenAPIRenderer)
UI_RENDERERS = {
'swagger': (SwaggerUIRenderer, ReDocRenderer),
'redoc': (ReDocRenderer, SwaggerUIRenderer),
'redoc-old': (ReDocOldRenderer, ReDocRenderer, SwaggerUIRenderer),
}
def deferred_never_cache(view_func):
"""
Decorator that adds headers to a response so that it will
never be cached.
"""
@wraps(view_func, assigned=WRAPPER_ASSIGNMENTS)
def _wrapped_view_func(request, *args, **kwargs):
response = view_func(request, *args, **kwargs)
# It is necessary to defer the add_never_cache_headers call because
# cache_page also defers its cache update operation; if we do not defer
# this, cache_page will give up because it will see and obey the "never
# cache" headers
def callback(response):
add_never_cache_headers(response)
return response
response.add_post_render_callback(callback)
return response
return _wrapped_view_func
def get_schema_view(info=None, url=None, patterns=None, urlconf=None, public=False, validators=None,
generator_class=None, authentication_classes=None, permission_classes=None):
"""Create a SchemaView class with default renderers and generators.
:param .Info info: information about the API; if omitted, defaults to :ref:`DEFAULT_INFO <default-swagger-settings>`
:param str url: same as :class:`.OpenAPISchemaGenerator`
:param patterns: same as :class:`.OpenAPISchemaGenerator`
:param urlconf: same as :class:`.OpenAPISchemaGenerator`
:param bool public: if False, includes only the endpoints that are accesible by the user viewing the schema
:param list validators: a list of validator names to apply; the only allowed value is ``ssv``, for now
:param type generator_class: schema generator class to use; should be a subclass of :class:`.OpenAPISchemaGenerator`
:param tuple authentication_classes: authentication classes for the schema view itself
:param tuple permission_classes: permission classes for the schema view itself
:return: SchemaView class
:rtype: type[drf_yasg.views.SchemaView]
"""
_public = public
_generator_class = generator_class or swagger_settings.DEFAULT_GENERATOR_CLASS
_auth_classes = authentication_classes
if _auth_classes is None:
_auth_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
_perm_classes = permission_classes
if _perm_classes is None:
_perm_classes = api_settings.DEFAULT_PERMISSION_CLASSES
info = info or swagger_settings.DEFAULT_INFO
validators = validators or []
_spec_renderers = tuple(renderer.with_validators(validators) for renderer in SPEC_RENDERERS)
class SchemaView(APIView):
_ignore_model_permissions = True
schema = None # exclude from schema
public = _public
generator_class = _generator_class
authentication_classes = _auth_classes
permission_classes = _perm_classes
renderer_classes = _spec_renderers
def get(self, request, version='', format=None):
version = request.version or version or ''
if isinstance(request.accepted_renderer, _SpecRenderer):
generator = self.generator_class(info, version, url, patterns, urlconf)
else:
generator = self.generator_class(info, version, url, patterns=[])
schema = generator.get_schema(request, self.public)
if schema is None:
raise exceptions.PermissionDenied() # pragma: no cover
return Response(schema)
@classmethod
def apply_cache(cls, view, cache_timeout, cache_kwargs):
"""Override this method to customize how caching is applied to the view.
Arguments described in :meth:`.as_cached_view`.
"""
view = vary_on_headers('Cookie', 'Authorization')(view)
view = cache_page(cache_timeout, **cache_kwargs)(view)
view = deferred_never_cache(view) # disable in-browser caching
return view
@classmethod
def as_cached_view(cls, cache_timeout=0, cache_kwargs=None, **initkwargs):
"""
Calls .as_view() and wraps the result in a cache_page decorator.
See https://docs.djangoproject.com/en/dev/topics/cache/
:param int cache_timeout: same as cache_page; set to 0 for no cache
:param dict cache_kwargs: dictionary of kwargs to be passed to cache_page
:param initkwargs: kwargs for .as_view()
:return: a view instance
"""
cache_kwargs = cache_kwargs or {}
view = cls.as_view(**initkwargs)
if cache_timeout != 0:
view = cls.apply_cache(view, cache_timeout, cache_kwargs)
elif cache_kwargs:
warnings.warn("cache_kwargs ignored because cache_timeout is 0 (disabled)")
return view
@classmethod
def without_ui(cls, cache_timeout=0, cache_kwargs=None):
"""
Instantiate this view with just JSON and YAML renderers, optionally wrapped with cache_page.
See https://docs.djangoproject.com/en/dev/topics/cache/.
:param int cache_timeout: same as cache_page; set to 0 for no cache
:param dict cache_kwargs: dictionary of kwargs to be passed to cache_page
:return: a view instance
"""
return cls.as_cached_view(cache_timeout, cache_kwargs, renderer_classes=_spec_renderers)
@classmethod
def with_ui(cls, renderer='swagger', cache_timeout=0, cache_kwargs=None):
"""
Instantiate this view with a Web UI renderer, optionally wrapped with cache_page.
See https://docs.djangoproject.com/en/dev/topics/cache/.
:param str renderer: UI renderer; allowed values are ``swagger``, ``redoc``
:param int cache_timeout: same as cache_page; set to 0 for no cache
:param dict cache_kwargs: dictionary of kwargs to be passed to cache_page
:return: a view instance
"""
assert renderer in UI_RENDERERS, "supported default renderers are " + ", ".join(UI_RENDERERS)
renderer_classes = UI_RENDERERS[renderer] + _spec_renderers
return cls.as_cached_view(cache_timeout, cache_kwargs, renderer_classes=renderer_classes)
return SchemaView