Drf-yasg не включает часть "api/" в урлы
Я использую drf-yasg для генерации схемы Swagger, но он удаляет часть "api/" из url.
schema_view = get_schema_view(
openapi.Info(
title="My API",
default_version='v1',
description="...",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="hello@mycompany.com"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
)
router = routers.DefaultRouter()
router.register(r'spaces', SpacesViewSet, basename='spaces')
urlpatterns = [
url(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
path('api/', include(router.urls)),
path('api/search-options', SearchPlacesOptionsView.as_view()),
]
Как вы можете видеть для маршрутов от drf-маршрутизатора, он не включает /api часть url. Однако для обычной конечной точки api/search-options он также удаляет часть /api, поэтому я не думаю, что это как-то связано с маршрутизатором.
У меня был такой же вопрос, и я не видел ни одного ответа на него, поэтому я исправил его и хочу поделиться с вами Я предполагаю, что эта проблема возникла потому, что у них было много изменений в их пакете (drf_yasg).
Вам следует переопределить метод get_paths() OpenAPISchemaGenerator и внести в него некоторые изменения,
Оригинальный OpenAPISchemaGenerator в классе drf_yasg:
class OpenAPISchemaGenerator(object):
# other methods ...
def get_paths(self, endpoints, components, request, public):
"""Generate the Swagger Paths for the API from the given endpoints.
:param dict endpoints: endpoints as returned by get_endpoints
:param ReferenceResolver components: resolver/container for Swagger References
:param Request request: the request made against the schema view; can be None
:param bool public: if True, all endpoints are included regardless of access through `request`
:returns: the :class:`.Paths` object and the longest common path prefix, as a 2-tuple
:rtype: tuple[openapi.Paths,str]
"""
if not endpoints:
return openapi.Paths(paths={}), ''
prefix = self.determine_path_prefix(list(endpoints.keys())) or ''
assert '{' not in prefix, "base path cannot be templated in swagger 2.0"
paths = OrderedDict()
for path, (view_cls, methods) in sorted(endpoints.items()):
operations = {}
for method, view in methods:
if not self.should_include_endpoint(path, method, view, public):
continue
operation = self.get_operation(view, path, prefix, method, components, request)
if operation is not None:
operations[method.lower()] = operation
if operations:
# since the common prefix is used as the API basePath, it must be stripped
# from individual paths when writing them into the swagger document
path_suffix = path[len(prefix):]
if not path_suffix.startswith('/'):
path_suffix = '/' + path_suffix
paths[path_suffix] = self.get_path_item(path, view_cls, operations)
return self.get_paths_object(paths), prefix
переопределить OpenAPISchemaGenerator в моем приложении Класс CustomizedOpenAPISchemaGenerator:
from collections import OrderedDict
from drf_yasg import openapi
from drf_yasg.generators import OpenAPISchemaGenerator
class CustomizedOpenAPISchemaGenerator(OpenAPISchemaGenerator):
def get_paths(self, endpoints, components, request, public):
if not endpoints:
return openapi.Paths(paths={}), ''
prefix = self.determine_path_prefix(list(endpoints.keys())) or ''
assert '{' not in prefix, "base path cannot be templated in swagger 2.0"
paths = OrderedDict()
for path, (view_cls, methods) in sorted(endpoints.items()):
operations = {}
for method, view in methods:
if not self.should_include_endpoint(path, method, view, public):
continue
operation = self.get_operation(view, path, prefix, method, components, request)
if operation is not None:
operations[method.lower()] = operation
if operations:
path_suffix = path[len(prefix):]
if not path_suffix.startswith('/'):
path_suffix = '/' + path_suffix
paths[path] = self.get_path_item(path, view_cls, operations)
# Only override this above line of upper level class paths[path_suffix] = ... to paths[path] = ...
return self.get_paths_object(paths), prefix
Я заменяю только это:
paths[path_suffix] = self.get_path_item(path, view_cls, operations)
с этим:
paths[path] = self.get_path_item(path, view_cls, operations)
После этого необходимо указать путь к новому классу генератора в конфигурации swagger, для этого у вас есть два варианта:
1: Используйте файл настроек django:
SWAGGER_SETTINGS = {
'DEFAULT_GENERATOR_CLASS': 'path.to.CustomizedOpenAPISchemaGenerator',
}
- аргумент path generator_class в функции get_schema_view():
schema_view = get_schema_view(
# your other data
generator_class=path.to.CustomizedOpenAPISchemaGenerator
)