From 3c0d17c6abc836bc78d7ab36b03c7242286d49f7 Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Thu, 14 Sep 2017 10:10:05 +0200 Subject: [PATCH] Adjust ManualSchema to take `fields` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … and `description`. Allows `url` and `action` to remain dynamic --- docs/api-guide/schemas.md | 53 ++++++++++++++++++++-------- rest_framework/schemas/inspectors.py | 30 +++++++++++++--- tests/test_schemas.py | 45 +++++++++++++++++++---- 3 files changed, 102 insertions(+), 26 deletions(-) diff --git a/docs/api-guide/schemas.md b/docs/api-guide/schemas.md index 5fc335ea68c..f913f046f6f 100644 --- a/docs/api-guide/schemas.md +++ b/docs/api-guide/schemas.md @@ -199,17 +199,28 @@ To customise the `Link` generation you may: This provides complete control over view introspection. -* Instantiate `ManualSchema` on your view, providing the Core API `Link` - explicitly: +* Instantiate `ManualSchema` on your view, providing the Core API `Fields` for + the view explicitly: from rest_framework.views import APIView from rest_framework.schemas import ManualSchema class CustomView(APIView): ... - schema = ManualSchema( - coreapi.Link(...) - ) + schema = ManualSchema(fields=[ + coreapi.Field( + "first_field", + required=True, + location="path", + schema=coreschema.String() + ), + coreapi.Field( + "second_field", + required=True, + location="path", + schema=coreschema.String() + ), + ]) This allows manually specifying the schema for some views whilst maintaining automatic generation elsewhere. @@ -580,17 +591,31 @@ Return a list of `coreapi.Link()` instances, as returned by the `get_schema_fiel ## ManualSchema -Allows specifying a manual schema for a view: +Allows manually providing a list of `coreapi.Field` instances for the schema, +plus an optional description. class MyView(APIView): - schema = ManualSchema(coreapi.Link( - url='/example/', - action='get', - fields=[] - )) - -The `ManualSchema` constructor takes a single parameter `link`, -the `coreapi.Link` instance for the view. + schema = ManualSchema(fields=[ + coreapi.Field( + "first_field", + required=True, + location="path", + schema=coreschema.String() + ), + coreapi.Field( + "second_field", + required=True, + location="path", + schema=coreschema.String() + ), + ] + ) + +The `ManualSchema` constructor takes two arguments: + +**`fields`**: A list of `coreapi.Field` instances. Required. + +**`description`**: A string description. Optional. --- diff --git a/rest_framework/schemas/inspectors.py b/rest_framework/schemas/inspectors.py index a99e9453b8c..b1dae678f19 100644 --- a/rest_framework/schemas/inspectors.py +++ b/rest_framework/schemas/inspectors.py @@ -364,11 +364,31 @@ def get_encoding(self, path, method): class ManualSchema(ViewInspector): """ - Overrides get_link to return manually specified schema. + Allows providing a list of coreapi.Fields, + plus an optional description. """ - def __init__(self, link): - assert isinstance(link, coreapi.Link) - self._link = link + def __init__(self, fields, description=''): + """ + Parameters: + + * `fields`: list of `coreapi.Field` instances. + * `descripton`: String description for view. Optional. + """ + assert all(isinstance(f, coreapi.Field) for f in fields), "`fields` must be a list of coreapi.Field instances" + self._fields = fields + self._description = description + + def get_link(self, path, method, base_url): + + if base_url and path.startswith('/'): + path = path[1:] + + return coreapi.Link( + url=urlparse.urljoin(base_url, path), + action=method.lower(), + encoding=None, + fields=self._fields, + description=self._description + ) - def get_link(self, *args): return self._link diff --git a/tests/test_schemas.py b/tests/test_schemas.py index 28fab41c2e7..14ed0f6b6f8 100644 --- a/tests/test_schemas.py +++ b/tests/test_schemas.py @@ -534,15 +534,46 @@ class CustomView(APIView): def test_view_with_manual_schema(self): - expected = coreapi.Link( - url='/example/', - action='get', - fields=[] - ) + path = '/example' + method = 'get' + base_url = None + + fields = [ + coreapi.Field( + "first_field", + required=True, + location="path", + schema=coreschema.String() + ), + coreapi.Field( + "second_field", + required=True, + location="path", + schema=coreschema.String() + ), + coreapi.Field( + "third_field", + required=True, + location="path", + schema=coreschema.String() + ), + ] + description = "A test endpoint" class CustomView(APIView): - schema = ManualSchema(expected) + """ + ManualSchema takes list of fields for endpoint. + - Provides url and action, which are always dynamic + """ + schema = ManualSchema(fields, description) + + expected = coreapi.Link( + url=path, + action=method, + fields=fields, + description=description + ) view = CustomView() - link = view.schema.get_link() + link = view.schema.get_link(path, method, base_url) assert link == expected