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).
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