Skip to content

Commit 65237d8

Browse files
committed
Add manual_fields kwarg to AutoSchema
1 parent a803345 commit 65237d8

File tree

3 files changed

+58
-8
lines changed

3 files changed

+58
-8
lines changed

docs/api-guide/schemas.md

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,7 @@ appropriate Core API `Link` object for the view, request method and path:
164164
auto_schema = view.schema
165165
coreapi_link = auto_schema.get_link(...)
166166

167-
168-
(Aside: In compiling the schema, `SchemaGenerator` calls `view.schema.get_link()` for
167+
(In compiling the schema, `SchemaGenerator` calls `view.schema.get_link()` for
169168
each view, allowed method and path.)
170169

171170
To customise the `Link` generation you may:
@@ -178,9 +177,9 @@ To customise the `Link` generation you may:
178177
class CustomView(APIView):
179178
...
180179
schema = AutoSchema(
181-
manual_fields= {
182-
"extra_field": coreapi.Field(...)
183-
}
180+
manual_fields=[
181+
coreapi.Field("extra_field", ...),
182+
]
184183
)
185184

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

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

515-
Typically you will subclass `AutoSchema` to customise schema generation
516-
and then set your subclass on your view.
514+
The `AutoSchema` constructor takes a single keyword argument `manual_fields`.
515+
516+
### `manual_fields`: a `list` of `coreapi.Field` instances that will be added to
517+
the generated fields. Generated fields with a matching `name` will be overwritten.
517518

519+
class CustomView(APIView):
520+
schema = AutoSchema(manual_fields=[
521+
coreapi.Field(
522+
"my_extra_field",
523+
required=True,
524+
location="path",
525+
schema=coreschema.String()
526+
),
527+
])
528+
529+
For more advanced customisation subclass `AutoSchema` to customise schema generation.
518530

519531
class CustomViewSchema(AutoSchema):
520532
"""
@@ -529,10 +541,13 @@ and then set your subclass on your view.
529541
class MyView(APIView):
530542
schema = CustomViewSchema()
531543

544+
The following methods are available to override.
545+
532546
### get_link(self, path, method, base_url)
533547

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

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

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

566581
## ManualSchema
567582

568-
`APIViewSchemaDescriptor` subclass for specifying a manual schema.
583+
Allows specifying a manual schema for a view:
569584

570585
class MyView(APIView):
571586
schema = ManualSchema(coreapi.Link(

rest_framework/schemas.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,12 +301,28 @@ class AutoSchema(ViewInspector):
301301
302302
Responsible for per-view instrospection and schema generation.
303303
"""
304+
def __init__(self, manual_fields=None):
305+
"""
306+
Parameters:
307+
308+
* `manual_fields`: list of `coreapi.Field` instances that
309+
will be added to auto-generated fields, overwriting on `Field.name`
310+
"""
311+
312+
self._manual_fields = manual_fields
313+
304314
def get_link(self, path, method, base_url):
305315
fields = self.get_path_fields(path, method)
306316
fields += self.get_serializer_fields(path, method)
307317
fields += self.get_pagination_fields(path, method)
308318
fields += self.get_filter_fields(path, method)
309319

320+
if self._manual_fields is not None:
321+
by_name = {f.name: f for f in fields}
322+
for f in self._manual_fields:
323+
by_name[f.name] = f
324+
fields = list(by_name.values())
325+
310326
if fields and any([field.location in ('form', 'body') for field in fields]):
311327
encoding = self.get_encoding(path, method)
312328
else:

tests/test_schemas.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,25 @@ def test_get_link_requires_instance(self):
513513
with pytest.raises(AssertionError):
514514
descriptor.get_link(None, None, None) # ???: Do the dummy arguments require a tighter assert?
515515

516+
def test_manual_fields(self):
517+
518+
class CustomView(APIView):
519+
schema = AutoSchema(manual_fields=[
520+
coreapi.Field(
521+
"my_extra_field",
522+
required=True,
523+
location="path",
524+
schema=coreschema.String()
525+
),
526+
])
527+
528+
view = CustomView()
529+
link = view.schema.get_link('/a/url/{id}/', 'GET', '')
530+
fields = link.fields
531+
532+
assert len(fields) == 2
533+
assert "my_extra_field" in [f.name for f in fields]
534+
516535
def test_view_with_manual_schema(self):
517536

518537
expected = coreapi.Link(

0 commit comments

Comments
 (0)