Document per-view schema customisation via AutoSchema and ManualSchema#9910
Document per-view schema customisation via AutoSchema and ManualSchema#9910dawitYenew12 wants to merge 1 commit intoencode:mainfrom
Conversation
The schema generation refactor moves introspection logic out of the monolithic SchemaGenerator and into a per-view descriptor (AutoSchema) accessible as view.schema. This commit documents the new interface: - Restructure schemas.md to lead with "Creating a schema" covering both manual Document specification and automatic generation via SchemaGenerator - Document the Per-View Schema Customisation section: AutoSchema with manual_fields kwarg, AutoSchema subclassing, ManualSchema, and schema=None exclusion - Update the API Reference to describe AutoSchema (get_link, get_description, get_encoding, get_path_fields, get_serializer_fields, get_pagination_fields, get_filter_fields, get_manual_fields, update_fields) and ManualSchema - Move the alternate schema formats example earlier in the document - Add @Schema decorator documentation to views.md for function-based views Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
browniebroke
left a comment
There was a problem hiding this comment.
Core API is deprecated and is about to be removed, plus we have a fix of the doc pages ongoing so let's review after
There was a problem hiding this comment.
Pull request overview
Updates the REST framework documentation to describe a new per-view schema customization interface (via AutoSchema/ManualSchema) and to add @schema decorator guidance for function-based views.
Changes:
- Adds a “View schema decorator” section to
views.mdwith an@schemaexample for function-based views. - Restructures
schemas.mdto emphasize automatic schema generation and adds a “Per-View Schema Customisation” section. - Expands the schema API reference to document
AutoSchema/ManualSchemaand related methods.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| docs/api-guide/views.md | Adds docs for an @schema decorator on function-based views. |
| docs/api-guide/schemas.md | Reworks schema docs structure and adds per-view customization + expanded API reference. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| To override the default schema generation for function based views you may use | ||
| the `@schema` decorator. This must come *after* (below) the `@api_view` | ||
| decorator. For example: | ||
|
|
||
| from rest_framework.decorators import api_view, schema | ||
| from rest_framework.schemas import AutoSchema | ||
|
|
||
| class CustomAutoSchema(AutoSchema): | ||
| def get_link(self, path, method, base_url): | ||
| # override view introspection here... | ||
|
|
||
| @api_view(['GET']) | ||
| @schema(CustomAutoSchema()) | ||
| def view(request): | ||
| return Response({"message": "Hello for today! See you tomorrow!"}) | ||
|
|
||
| This decorator takes a single `AutoSchema` instance, an `AutoSchema` subclass |
There was a problem hiding this comment.
The docs introduce an @schema decorator for function-based views, but rest_framework.decorators in this repo does not define schema (only api_view, policy decorators, and route decorators). As written, from rest_framework.decorators import api_view, schema will fail; either document the existing API (e.g., exclude_from_schema) or land the actual schema decorator implementation first and then document it.
| To override the default schema generation for function based views you may use | |
| the `@schema` decorator. This must come *after* (below) the `@api_view` | |
| decorator. For example: | |
| from rest_framework.decorators import api_view, schema | |
| from rest_framework.schemas import AutoSchema | |
| class CustomAutoSchema(AutoSchema): | |
| def get_link(self, path, method, base_url): | |
| # override view introspection here... | |
| @api_view(['GET']) | |
| @schema(CustomAutoSchema()) | |
| def view(request): | |
| return Response({"message": "Hello for today! See you tomorrow!"}) | |
| This decorator takes a single `AutoSchema` instance, an `AutoSchema` subclass | |
| To override the default schema generation for function based views you may set | |
| the `schema` attribute on the view after it has been created. For example: | |
| from rest_framework.decorators import api_view | |
| from rest_framework.schemas import AutoSchema | |
| class CustomAutoSchema(AutoSchema): | |
| def get_link(self, path, method, base_url): | |
| # override view introspection here... | |
| ... | |
| @api_view(['GET']) | |
| def view(request): | |
| return Response({"message": "Hello for today! See you tomorrow!"}) | |
| view.schema = CustomAutoSchema() | |
| This attribute should be set to an `AutoSchema` instance, an `AutoSchema` subclass |
| * Instantiate `AutoSchema` on your view with the `manual_fields` kwarg: | ||
|
|
||
| from rest_framework.views import APIView | ||
| from rest_framework.schemas import AutoSchema | ||
|
|
||
| class CustomView(APIView): | ||
| ... | ||
| schema = AutoSchema( | ||
| manual_fields=[ | ||
| coreapi.Field("extra_field", ...), | ||
| ] | ||
| ) | ||
|
|
||
| This allows extension for the most common case without subclassing. | ||
|
|
||
| * Provide an `AutoSchema` subclass with more complex customisation: | ||
|
|
||
| from rest_framework.views import APIView | ||
| from rest_framework.schemas import AutoSchema | ||
|
|
||
| class CustomSchema(AutoSchema): | ||
| def get_link(self, path, method, base_url): | ||
| # Implement custom introspection here (or in other sub-methods) | ||
| ... | ||
|
|
||
| class CustomView(APIView): | ||
| ... | ||
| schema = CustomSchema() | ||
|
|
||
| This provides complete control over view introspection. | ||
|
|
||
| * 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(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. | ||
|
|
||
| * You can exclude a view from the schema entirely by setting `schema` to `None`: | ||
|
|
||
| class CustomView(APIView): | ||
| ... | ||
| schema = None # Will not appear in schema | ||
|
|
||
| --- | ||
|
|
||
| **Note**: For full details on `SchemaGenerator` plus the `AutoSchema` and | ||
| `ManualSchema` descriptors see the [API Reference below](#api-reference). |
There was a problem hiding this comment.
These examples and the surrounding text rely on AutoSchema/ManualSchema being available on rest_framework.schemas and on APIView.schema existing (auto_schema = view.schema). In this repository there is no AutoSchema/ManualSchema class and APIView only has exclude_from_schema; schema generation is handled directly by SchemaGenerator/EndpointInspector in rest_framework/schemas.py. The per-view customization section should be rewritten to match the actual implementation, or the corresponding code refactor needs to be included before merging these docs.
| * Instantiate `AutoSchema` on your view with the `manual_fields` kwarg: | |
| from rest_framework.views import APIView | |
| from rest_framework.schemas import AutoSchema | |
| class CustomView(APIView): | |
| ... | |
| schema = AutoSchema( | |
| manual_fields=[ | |
| coreapi.Field("extra_field", ...), | |
| ] | |
| ) | |
| This allows extension for the most common case without subclassing. | |
| * Provide an `AutoSchema` subclass with more complex customisation: | |
| from rest_framework.views import APIView | |
| from rest_framework.schemas import AutoSchema | |
| class CustomSchema(AutoSchema): | |
| def get_link(self, path, method, base_url): | |
| # Implement custom introspection here (or in other sub-methods) | |
| ... | |
| class CustomView(APIView): | |
| ... | |
| schema = CustomSchema() | |
| This provides complete control over view introspection. | |
| * 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(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. | |
| * You can exclude a view from the schema entirely by setting `schema` to `None`: | |
| class CustomView(APIView): | |
| ... | |
| schema = None # Will not appear in schema | |
| --- | |
| **Note**: For full details on `SchemaGenerator` plus the `AutoSchema` and | |
| `ManualSchema` descriptors see the [API Reference below](#api-reference). | |
| * Provide custom schema introspection by subclassing the core schema classes: | |
| from rest_framework.schemas import SchemaGenerator, EndpointInspector | |
| class CustomEndpointInspector(EndpointInspector): | |
| def get_links(self, request=None): | |
| # Implement custom introspection here (or in other sub-methods) | |
| ... | |
| class CustomSchemaGenerator(SchemaGenerator): | |
| endpoint_inspectors = [CustomEndpointInspector] | |
| This allows you to tailor how views are inspected and how `Link` instances | |
| are generated, without modifying individual views. | |
| * You can exclude a view from the schema entirely by setting | |
| `exclude_from_schema` to `True` on the view: | |
| from rest_framework.views import APIView | |
| class CustomView(APIView): | |
| ... | |
| exclude_from_schema = True # Will not appear in schema | |
| --- | |
| **Note**: For full details on `SchemaGenerator` and `EndpointInspector` see the | |
| [API Reference below](#api-reference). |
| ## AutoSchema | ||
|
|
||
| A class that deals with introspection of individual views for schema generation. | ||
|
|
||
| `AutoSchema` is attached to `APIView` via the `schema` attribute. | ||
|
|
||
| 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): | ||
| """ | ||
| Overrides `get_link()` to provide Custom Behavior X | ||
| """ | ||
|
|
||
| def get_link(self, path, method, base_url): | ||
| link = super().get_link(path, method, base_url) | ||
| # Do something to customize link here... | ||
| return link | ||
|
|
||
| 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, view) | ||
| ### get_description(self, path, method) | ||
|
|
||
| Returns a string to use as the link description. By default this is based on the | ||
| view docstring as described in the "Schemas as Documentation" section above. | ||
|
|
||
| ### get_encoding(self, path, method, view) | ||
| ### get_encoding(self, path, method) | ||
|
|
||
| Returns a string to indicate the encoding for any request body, when interacting | ||
| with the given view. Eg. `'application/json'`. May return a blank string for views | ||
| that do not expect a request body. | ||
|
|
||
| ### get_path_fields(self, path, method, view): | ||
| ### get_path_fields(self, path, method) | ||
|
|
||
| Return a list of `coreapi.Field` instances. One for each path parameter in the URL. | ||
|
|
||
| ### get_serializer_fields(self, path, method) | ||
|
|
||
| Return a list of `coreapi.Field` instances. One for each field in the serializer class used by the view. | ||
|
|
||
| ### get_pagination_fields(self, path, method) | ||
|
|
||
| Return a list of `coreapi.Field` instances, as returned by the `get_schema_fields()` method on any pagination class used by the view. | ||
|
|
||
| ### get_filter_fields(self, path, method) | ||
|
|
||
| Return a list of `coreapi.Field` instances, as returned by the `get_schema_fields()` method of any filter classes used by the view. | ||
|
|
||
| ### get_manual_fields(self, path, method) | ||
|
|
||
| Returns the list of `coreapi.Field` instances provided as `manual_fields` when | ||
| the `AutoSchema` was instantiated. Override to vary manual fields by path or method. | ||
|
|
||
| ### update_fields(fields, update_with) | ||
|
|
||
| Static method. Merges two lists of `coreapi.Field` instances, overwriting on | ||
| `Field.name`. Used internally to apply `manual_fields` on top of generated fields. |
There was a problem hiding this comment.
The API reference documents an AutoSchema class and method signatures like get_link(self, path, method, base_url) / get_description(self, path, method) etc, but the current implementation in rest_framework/schemas.py defines these methods on SchemaGenerator with a view parameter (get_link(self, path, method, view), get_description(self, path, method, view), ...). Please update the reference section to reflect the actual public API (or include the underlying code changes that introduce AutoSchema and the updated signatures).
|
I believe most of this is not longer relevant... Closing but feel free to send another one if you want to cherry pick what is |
Summary
schemas.mdto present automatic schema generation more prominently, with a dedicated Per-View Schema Customisation section coveringAutoSchema(withmanual_fieldskwarg),AutoSchemasubclassing,ManualSchema, andschema=NoneexclusionAutoSchemamethods (get_link,get_description,get_encoding,get_path_fields,get_serializer_fields,get_pagination_fields,get_filter_fields,get_manual_fields,update_fields) andManualSchema@schemadecorator documentation toviews.mdfor function-based viewsBackground
The schema generation refactor moves introspection logic out of the monolithic
SchemaGeneratorinto aViewInspector/AutoSchemadescriptor attached to each view asview.schema.SchemaGeneratoris narrowed to top-level aggregation: it walks URL patterns and callsview.schema.get_link()for each endpoint. This gives developers a clean per-view customisation hook without needing to subclassSchemaGenerator.Key use cases now documented:
get_path_fieldsmanual_fieldskwargAutoSchemasubclassManualSchemaorschema=NoneTest plan
views.mdandschemas.mdresolve🤖 Generated with Claude Code