Skip to content

Document per-view schema customisation via AutoSchema and ManualSchema#9910

Open
dawitYenew12 wants to merge 1 commit intoencode:mainfrom
dawitYenew12:hfi/drf-schema-docs/B
Open

Document per-view schema customisation via AutoSchema and ManualSchema#9910
dawitYenew12 wants to merge 1 commit intoencode:mainfrom
dawitYenew12:hfi/drf-schema-docs/B

Conversation

@dawitYenew12
Copy link

Summary

  • Documents the new per-view schema descriptor interface introduced by the schema generation refactor
  • Restructures schemas.md to present automatic schema generation more prominently, with a dedicated Per-View Schema Customisation section covering AutoSchema (with manual_fields kwarg), AutoSchema subclassing, ManualSchema, and schema=None exclusion
  • Expands the API Reference with full documentation for AutoSchema methods (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
  • Adds @schema decorator documentation to views.md for function-based views

Background

The schema generation refactor moves introspection logic out of the monolithic SchemaGenerator into a ViewInspector/AutoSchema descriptor attached to each view as view.schema. SchemaGenerator is narrowed to top-level aggregation: it walks URL patterns and calls view.schema.get_link() for each endpoint. This gives developers a clean per-view customisation hook without needing to subclass SchemaGenerator.

Key use cases now documented:

  • Adding a description to a non-model path parameter by overriding get_path_fields
  • Providing extra fields without subclassing via manual_fields kwarg
  • Full control via AutoSchema subclass
  • Opting out of automatic generation for a specific view via ManualSchema or schema=None

Test plan

  • Verify rendered documentation in MkDocs locally
  • Check all code examples are syntactically correct
  • Confirm links between views.md and schemas.md resolve

🤖 Generated with Claude Code

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>
Copy link
Member

@browniebroke browniebroke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.md with an @schema example for function-based views.
  • Restructures schemas.md to emphasize automatic schema generation and adds a “Per-View Schema Customisation” section.
  • Expands the schema API reference to document AutoSchema/ManualSchema and 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.

Comment on lines +190 to +206
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
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
Comment on lines +169 to +235
* 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).
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
* 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).

Copilot uses AI. Check for mistakes.
Comment on lines +523 to +603
## 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.
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants