4

一个使用 Django、DRF、swagger 的项目。

网址配置如下:

schema_view = get_swagger_view(title='Pastebin API')
urlpatterns = [
    url(r'^$', schema_view),
    url(r'store', include('store.urls')),
    ... # other urls using routers.SimplerRouter
]

和存储/urls.py:

router = routers.SimpleRouter()
router.register(r'', views.StoreViewSet)
urlpatterns = router.urls

和views.StoreViewSet:

class StoreViewSet(BaseObject, GenericViewSet):
    permition_class = ()

    @list_route()
    def detail(self, request):
        return {}

    @list_route(url_path='detail/export')
    def detail_export(self, request):
        return {}

之后python manage.py runserver,访问http://127.0.0.1:8000/#并发生 TypeError:

File "/usr/local/share/.virtualenvs/dev-finance/lib/python2.7/site-packages/rest_framework_swagger/views.py", line 32, in get
schema = generator.get_schema(request=request)
File "/usr/local/share/.virtualenvs/dev-finance/lib/python2.7/site-packages/rest_framework/schemas.py", line 242, in get_schema
links = self.get_links(request)
File "/usr/local/share/.virtualenvs/dev-finance/lib/python2.7/site-packages/rest_framework/schemas.py", line 276, in get_links
insert_into(links, keys, link)
File "/usr/local/share/.virtualenvs/dev-finance/lib/python2.7/site-packages/rest_framework/schemas.py", line 79, in insert_into
target[keys[-1]] = value
TypeError: 'Link' object does not support item assignment
[ERROR] 2017-05-04 15:25:06,936 log_message(basehttp.py:131) "GET / HTTP/1.1" 500 20384

错误消息显示,Link对象不能像 dict 一样赋值。

如果我将方法名称从detail_exportto重命名details_export,一切都会再次正常。

rest_framework 的@list_route装饰器将方法的 url 传递给 Link 对象时发生猜测错误。

为什么其他方法就好了?我该如何解决这个问题?

4

2 回答 2

3

这是DRF 中的错误。可能,它将在 3.6.4 中修复。现在你可以:

  1. 删除url_pathlist_route

    class StoreViewSet(BaseObject, GenericViewSet):
        permition_class = ()
    
        @list_route()
        def detail(self, request):
            return {}
    
        @list_route()
        def detail_export(self, request):
            return {}
    
  2. 或者使用带有自定义SchemaView的自定义SchemaGenerator

    # api/schema.py for example
    
    from rest_framework.permissions import AllowAny
    from rest_framework.renderers import CoreJSONRenderer
    from rest_framework.response import Response
    from rest_framework.schemas import SchemaGenerator
    from rest_framework.views import APIView
    from rest_framework_swagger import renderers
    
    
    class CustomSchemaGenerator(SchemaGenerator):
        def get_keys(self, subpath, method, view):
            result = super().get_keys(subpath, method, view)
            # here you can fix your path
            if result == ['store', 'detail', 'detail_export']:  
                return ['store', 'detail_export'] 
            return result
    
    
    class SwaggerSchemaView(APIView):
        _ignore_model_permissions = True
        exclude_from_schema = True
        permission_classes = [AllowAny]
        renderer_classes = [
            CoreJSONRenderer,
            renderers.OpenAPIRenderer,
            renderers.SwaggerUIRenderer
        ]
    
        def get(self, request):
            generator = CustomSchemaGenerator(title='API')
            return Response(generator.get_schema(request=request))
    
    # urls.py
    
    from django.contrib.auth.decorators import login_required
    from api.schema import SwaggerSchemaView   
    
    urlpatterns = [
        # ...
        url(r'^swagger-url/', login_required(SwaggerSchemaView.as_view()))
        # ...
    ]
    
于 2017-07-26T10:00:46.730 回答
1

这是一个黑客:

  1. 打开你的环境文件夹/lib/python3.5/site-packages/rest_framework/schemas.py
  2. 查找“insert_into”函数
  3. 替换这个:

    target[keys[-1]] = value
    

有了这个:

if type(target) != coreapi.Link:
    target[keys[-1]] = value
于 2017-07-10T22:44:57.317 回答