Skip to content

Commit

Permalink
Add manual_fields kwarg to AutoSchema
Browse files Browse the repository at this point in the history
  • Loading branch information
carltongibson committed Aug 30, 2017
1 parent a803345 commit 65237d8
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 8 deletions.
31 changes: 23 additions & 8 deletions docs/api-guide/schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,7 @@ appropriate Core API `Link` object for the view, request method and path:
auto_schema = view.schema
coreapi_link = auto_schema.get_link(...)


(Aside: In compiling the schema, `SchemaGenerator` calls `view.schema.get_link()` for
(In compiling the schema, `SchemaGenerator` calls `view.schema.get_link()` for
each view, allowed method and path.)

To customise the `Link` generation you may:
Expand All @@ -178,9 +177,9 @@ To customise the `Link` generation you may:
class CustomView(APIView):
...
schema = AutoSchema(
manual_fields= {
"extra_field": coreapi.Field(...)
}
manual_fields=[
coreapi.Field("extra_field", ...),
]
)

This allows extension for the most common case without subclassing.
Expand Down Expand Up @@ -512,9 +511,22 @@ A class that deals with introspection of individual views for schema generation.

`AutoSchema` is attached to `APIView` via the `schema` attribute.

Typically you will subclass `AutoSchema` to customise schema generation
and then set your subclass on your view.
The `AutoSchema` constructor takes a single keyword argument `manual_fields`.

### `manual_fields`: a `list` of `coreapi.Field` instances that will be added to
the generated fields. Generated fields with a matching `name` will be overwritten.

class CustomView(APIView):
schema = AutoSchema(manual_fields=[
coreapi.Field(
"my_extra_field",
required=True,
location="path",
schema=coreschema.String()
),
])

For more advanced customisation subclass `AutoSchema` to customise schema generation.

class CustomViewSchema(AutoSchema):
"""
Expand All @@ -529,10 +541,13 @@ and then set your subclass on your view.
class MyView(APIView):
schema = CustomViewSchema()

The following methods are available to override.

### get_link(self, path, method, base_url)

Returns a `coreapi.Link` instance corresponding to the given view.

This is the main entry point.
You can override this if you need to provide custom behaviors for particular views.

### get_description(self, path, method)
Expand Down Expand Up @@ -565,7 +580,7 @@ Return a list of `coreapi.Link()` instances, as returned by the `get_schema_fiel

## ManualSchema

`APIViewSchemaDescriptor` subclass for specifying a manual schema.
Allows specifying a manual schema for a view:

class MyView(APIView):
schema = ManualSchema(coreapi.Link(
Expand Down
16 changes: 16 additions & 0 deletions rest_framework/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,28 @@ class AutoSchema(ViewInspector):
Responsible for per-view instrospection and schema generation.
"""
def __init__(self, manual_fields=None):
"""
Parameters:
* `manual_fields`: list of `coreapi.Field` instances that
will be added to auto-generated fields, overwriting on `Field.name`
"""

self._manual_fields = manual_fields

def get_link(self, path, method, base_url):
fields = self.get_path_fields(path, method)
fields += self.get_serializer_fields(path, method)
fields += self.get_pagination_fields(path, method)
fields += self.get_filter_fields(path, method)

if self._manual_fields is not None:
by_name = {f.name: f for f in fields}
for f in self._manual_fields:
by_name[f.name] = f
fields = list(by_name.values())

if fields and any([field.location in ('form', 'body') for field in fields]):
encoding = self.get_encoding(path, method)
else:
Expand Down
19 changes: 19 additions & 0 deletions tests/test_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,25 @@ def test_get_link_requires_instance(self):
with pytest.raises(AssertionError):
descriptor.get_link(None, None, None) # ???: Do the dummy arguments require a tighter assert?

def test_manual_fields(self):

class CustomView(APIView):
schema = AutoSchema(manual_fields=[
coreapi.Field(
"my_extra_field",
required=True,
location="path",
schema=coreschema.String()
),
])

view = CustomView()
link = view.schema.get_link('/a/url/{id}/', 'GET', '')
fields = link.fields

assert len(fields) == 2
assert "my_extra_field" in [f.name for f in fields]

def test_view_with_manual_schema(self):

expected = coreapi.Link(
Expand Down

0 comments on commit 65237d8

Please sign in to comment.