From 7f3c4188b96a5be93fbb130de8d576403e858120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20ROCHER?= Date: Thu, 28 Jul 2016 15:43:27 +0200 Subject: [PATCH] Prevent lower api to erase higher namespace Before, an API plugged to a namespace (for instance /account/{pk}/) would erase API plugged to the same namespace with additional URL segments: (for instance /account/{user_id}/book/{pk}/) --- rest_framework/schemas.py | 10 ++--- tests/test_schemas.py | 94 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 7 deletions(-) diff --git a/rest_framework/schemas.py b/rest_framework/schemas.py index d249ac4e1..5ce2e9e70 100644 --- a/rest_framework/schemas.py +++ b/rest_framework/schemas.py @@ -176,18 +176,16 @@ class SchemaGenerator(object): Return a tuple of strings, indicating the identity to use for a given endpoint. eg. ('users', 'list'). """ - category = None + category = [] for item in path.strip('/').split('/'): if '{' in item: - break - category = item + continue + category.append(item) actions = getattr(callback, 'actions', self.default_mapping) action = actions[method.lower()] - if category: - return (category, action) - return (action,) + return (' '.join(category), action) # Methods for generating each individual `Link` instance... diff --git a/tests/test_schemas.py b/tests/test_schemas.py index f5b49abcd..2a15e0e64 100644 --- a/tests/test_schemas.py +++ b/tests/test_schemas.py @@ -6,7 +6,7 @@ from django.test import TestCase, override_settings from rest_framework import filters, pagination, permissions, serializers from rest_framework.compat import coreapi from rest_framework.response import Response -from rest_framework.routers import DefaultRouter +from rest_framework.routers import DefaultRouter, SimpleRouter from rest_framework.schemas import SchemaGenerator from rest_framework.test import APIClient from rest_framework.views import APIView @@ -55,6 +55,14 @@ urlpatterns2 = [ ] +router = SimpleRouter() +router.register('example', ExampleViewSet, base_name='example') +urlpatterns3 = [ + url(r'^', include(router.urls)), + url(r'^(?P\w+)/example-view/$', ExampleView.as_view(), name='example-view') +] + + @unittest.skipUnless(coreapi, 'coreapi is not installed') @override_settings(ROOT_URLCONF='tests.test_schemas') class TestRouterGeneratedSchema(TestCase): @@ -179,3 +187,87 @@ class TestSchemaGenerator(TestCase): } ) self.assertEquals(schema, expected) + + +@unittest.skipUnless(coreapi, 'coreapi is not installed') +class TestSchemaAndSubSchemaGenerator(TestCase): + def test_view(self): + schema_generator = SchemaGenerator(title='Test View', patterns=urlpatterns3) + schema = schema_generator.get_schema() + expected = coreapi.Document( + url='', + title='Test View', + content={ + 'example': { + 'list': coreapi.Link( + url='/example/', + action='get', + fields=[ + coreapi.Field('page', required=False, location='query'), + coreapi.Field('ordering', required=False, location='query') + ] + ), + 'create': coreapi.Link( + url='/example/', + action='post', + encoding='application/json', + fields=[ + coreapi.Field('a', required=True, location='form', description='About a'), + coreapi.Field('b', required=False, location='form', description='About b') + ] + ), + 'retrieve': coreapi.Link( + url='/example/{pk}/', + action='get', + fields=[ + coreapi.Field('pk', required=True, location='path') + ] + ), + 'update': coreapi.Link( + url='/example/{pk}/', + action='put', + encoding='application/json', + fields=[ + coreapi.Field('pk', required=True, location='path'), + coreapi.Field('a', required=True, location='form', description='About a'), + coreapi.Field('b', required=False, location='form', description='About b') + ] + ), + 'partial_update': coreapi.Link( + url='/example/{pk}/', + action='patch', + encoding='application/json', + fields=[ + coreapi.Field('pk', required=True, location='path'), + coreapi.Field('a', required=False, location='form', description='About a'), + coreapi.Field('b', required=False, location='form', description='About b') + ] + ), + 'destroy': coreapi.Link( + url='/example/{pk}/', + action='delete', + fields=[ + coreapi.Field('pk', required=True, location='path') + ] + ) + }, + 'example-view': { + 'create': coreapi.Link( + url='/{example_id}/example-view/', + action='post', + fields=[ + coreapi.Field('example_id', required=True, location='path') + ] + ), + 'read': coreapi.Link( + url='/{example_id}/example-view/', + action='get', + description='get documentation', + fields=[ + coreapi.Field('example_id', required=True, location='path') + ] + ) + }, + } + ) + self.assertEquals(schema, expected)