Views API#
- class fastapi_restly.views.AsyncReactAdminView#
Bases:
_ReactAdminMixin,AsyncRestViewAsyncRestView that speaks the ra-data-simple-rest wire contract.
Use this instead of AsyncRestView when your frontend is react-admin with ra-data-simple-rest.
- async listing() Any#
- async put(id: Any, schema_obj: Any) Any#
- class fastapi_restly.views.AsyncRestView#
Bases:
BaseRestView[ModelT,SchemaT,CreateSchemaT,UpdateSchemaT,IdT]AsyncRestView creates an async CRUD/REST interface for database objects. Basic usage:
class FooView(AsyncRestView): prefix = "/foo" schema = FooRead model = Foo
Where
Foois a SQLAlchemy model andFooReada Pydantic model.- build_query() Select#
Return the base SQLAlchemy
Selectused by every read on this view’s model — listing, count, and retrieve. Override to addWHEREclauses that should apply to all of them — e.g. tenant scoping, soft-delete filtering, row-level permission visibility. Callsuper().build_query()and chain.where(...)to compose with any base-class or mixin filters.Because retrieve also routes through this query, a row hidden from listing cannot be fetched directly via
GET /{id}— visibility stays consistent across endpoints by construction.
- async count_listing(query: Select) int#
- async create(schema_obj: Any) Any#
- async delete(id: Any) Response#
- async get(id: Any) Any#
- async listing(query_params: Any) Any#
- async perform_create(schema_obj: CreateSchemaT) ModelT#
Handle a POST request on “/”. This should create a new object. Feel free to override this method.
- async perform_delete(id: IdT) Response#
- async perform_get(id: IdT) ModelT#
Handle a GET request on “/{id}”. This should return a single object. Return a 404 if not found.
Routes through
build_query(), so any read-side filters layered there (tenant scoping, soft-delete, row-level permissions) apply to retrieve as well — a row hidden from listing returns 404 here too, without a separate post-fetch guard.
- async perform_listing(query_params: Any) ListingResult[ModelT]#
Handle a GET request on “/”. This should return listed objects and the total count before pagination. Feel free to override this method, e.g.:
- async def perform_listing(self, query_params):
result = await super().perform_listing(query_params) return ListingResult(add_my_info(result.objects), result.total_count)
query_paramsis the validated query-parameter Pydantic model injected by FastAPI; pagination bounds (page/page_size) have already been validated by the schema returned fromfastapi_restly.query.create_list_params_schema().For WHERE-clause-only filtering that should also apply to the pagination total and to retrieve, override
build_query()instead.
- async perform_update(id: IdT, schema_obj: UpdateSchemaT) ModelT#
Handle a PATCH request on “/{id}”. This should partially update an existing object. Feel free to override this method.
- session: Annotated[AsyncSession, Depends(_async_generate_session)]#
- async update(id: Any, schema_obj: Any) Any#
- class fastapi_restly.views.BaseRestView#
Bases:
View,Generic[ModelT,SchemaT,CreateSchemaT,UpdateSchemaT,IdT]Base class for RestView implementations.
This class contains the common functionality shared between AsyncRestView and RestView, including schema definitions, model configuration, and common CRUD operation logic.
- classmethod before_include_view()#
Apply type annotations needed for FastAPI, before creating an APIRouter from this view and registering it.
This function can be overridden to further tweak the endpoints before they are added to FastAPI.
- creation_schema: ClassVar[type[BaseModel]]#
- default_page_size: ClassVar[int | None] = None#
Default
page_sizefor list endpoints.Nonemeans “no implicit cap” (the framework default). Override per-view.
- extra_query_params: ClassVar[Iterable[str]] = ()#
Extra query-parameter keys to allow on the listing endpoint in addition to those derived from the response schema. Use this when a view intentionally consumes a custom query parameter (e.g. an
?include_deleted=trueescape hatch on a soft-delete mixin) that isn’t a filter on a schema field. Without this, the strict unknown-key guard would reject the request with 422.
- get_relationship_loader_options() list[Any]#
- id_type#
alias of
int
- include_pagination_metadata: ClassVar[bool] = False#
- listing_param_schema: ClassVar[type[BaseModel]]#
- max_page_size: ClassVar[int] = 1000#
Maximum
page_sizeaccepted on list endpoints. Above this returns 422.
- model: ClassVar[type[DeclarativeBase]]#
- pagination_response_schema: ClassVar[type[BaseModel]]#
- request: Request#
- responses: ClassVar[dict[int | str, dict[str, Any]]] = {404: {'description': 'Not found'}}#
- schema: ClassVar[type[BaseModel]]#
- to_listing_response(query_params: Any, listing_result: ListingResult[ModelT]) Any#
- to_paginated_listing_response(query_params: Any, listing_result: ListingResult[Any]) dict[str, Any]#
- to_response_schema(obj: ModelT | SchemaT) SchemaT#
Serialize an ORM object to the configured response schema.
- update_schema: ClassVar[type[BaseModel]]#
- class fastapi_restly.views.ListingResult(objects: Sequence[ModelT], total_count: int)#
Bases:
Generic[ModelT]Result returned by
perform_listingbefore HTTP response formatting.- objects: Sequence[ModelT]#
- total_count: int#
- class fastapi_restly.views.ReactAdminView#
Bases:
_ReactAdminMixin,RestViewRestView that speaks the ra-data-simple-rest wire contract.
Use this instead of RestView when your frontend is react-admin with ra-data-simple-rest.
- listing() Any#
- put(id: Any, schema_obj: Any) Any#
- class fastapi_restly.views.RestView#
Bases:
BaseRestView[ModelT,SchemaT,CreateSchemaT,UpdateSchemaT,IdT]RestView creates a synchronous CRUD/REST interface for database objects. Basic usage:
class FooView(RestView): prefix = "/foo" schema = FooRead model = Foo
Where
Foois a SQLAlchemy model andFooReada Pydantic model.- build_query() Select#
Return the base SQLAlchemy
Selectused by every read on this view’s model — listing, count, and retrieve. Override to addWHEREclauses that should apply to all of them — e.g. tenant scoping, soft-delete filtering, row-level permission visibility. Callsuper().build_query()and chain.where(...)to compose with any base-class or mixin filters.Because retrieve also routes through this query, a row hidden from listing cannot be fetched directly via
GET /{id}— visibility stays consistent across endpoints by construction.
- count_listing(query: Select) int#
- create(schema_obj: Any) Any#
- delete(id: Any) Response#
- get(id: Any) Any#
- listing(query_params: Any) Any#
- perform_create(schema_obj: CreateSchemaT) ModelT#
Handle a POST request on “/”. This should create a new object. Feel free to override this method.
- perform_delete(id: IdT) Response#
- perform_get(id: IdT) ModelT#
Handle a GET request on “/{id}”. This should return a single object. Return a 404 if not found.
Routes through
build_query(), so any read-side filters layered there (tenant scoping, soft-delete, row-level permissions) apply to retrieve as well — a row hidden from listing returns 404 here too, without a separate post-fetch guard.
- perform_listing(query_params: Any) ListingResult[ModelT]#
Handle a GET request on “/”. This should return listed objects and the total count before pagination. Feel free to override this method, e.g.:
- def perform_listing(self, query_params):
result = super().perform_listing(query_params) return ListingResult(add_my_info(result.objects), result.total_count)
query_paramsis the validated query-parameter Pydantic model injected by FastAPI; pagination bounds (page/page_size) have already been validated by the schema returned fromfastapi_restly.query.create_list_params_schema().For WHERE-clause-only filtering that should also apply to the pagination total and to retrieve, override
build_query()instead.
- perform_update(id: IdT, schema_obj: UpdateSchemaT) ModelT#
Handle a PATCH request on “/{id}”. This should partially update an existing object. Feel free to override this method.
- session: Annotated[Session, Depends(_generate_session)]#
- update(id: Any, schema_obj: Any) Any#
- class fastapi_restly.views.View#
Bases:
objectClass-based view primitive for FastAPI.
Group related endpoints on a class, share dependencies and metadata via class attributes, and let subclasses override individual handlers. Routes are bound at
include_view()time, not at class-definition time, so subclassing works the way Python developers expect: override a method on a subclass and the override is what runs.Most users will subclass
RestVieworAsyncRestView, which extendViewwith CRUD scaffolding. UseViewdirectly for grouped non-CRUD endpoints (auth flows, custom RPC routes, etc.).- classmethod before_include_view()#
- dependencies: ClassVar[Any] = None#
- prefix: ClassVar[str]#
- responses: ClassVar[dict[int | str, dict[str, Any]]] = {}#
- tags: ClassVar[Any] = None#
- class fastapi_restly.views.ViewRoute(*values)#
Bases:
str,EnumGenerated CRUD routes that can be referenced by view options.
- CREATE = 'create'#
- DELETE = 'delete'#
- GET = 'get'#
- LIST = 'listing'#
- UPDATE = 'update'#
- fastapi_restly.views.delete(path: str, **api_route_kwargs: Any) Callable[[...], Any]#
Decorator to mark a View method as a DELETE endpoint.
Equivalent to:
@route(path, methods=["DELETE"], status_code=204, ... )
- fastapi_restly.views.get(path: str, **api_route_kwargs: Any) Callable[[...], Any]#
Decorator to mark a View method as a GET endpoint.
Equivalent to:
@route(path, methods=["GET"], status_code=200, ... )
- fastapi_restly.views.include_view(parent_router: APIRouter | FastAPI, view_cls: V | None = None) V | Callable[[V], V]#
Add a View class’s routes to a FastAPI app or APIRouter.
Prefer the direct call form from your app/router composition layer:
include_view(app, MyView)
For small apps, it can also be used as a decorator:
@include_view(app) class MyView(AsyncRestView): ...
- fastapi_restly.views.patch(path: str, **api_route_kwargs: Any) Callable[[...], Any]#
Decorator to mark a View method as a PATCH endpoint.
Equivalent to:
@route(path, methods=["PATCH"], status_code=200, ... )
- fastapi_restly.views.post(path: str, **api_route_kwargs: Any) Callable[[...], Any]#
Decorator to mark a View method as a POST endpoint.
Equivalent to:
@route(path, methods=["POST"], status_code=201, ... )
- fastapi_restly.views.put(path: str, **api_route_kwargs: Any) Callable[[...], Any]#
Decorator to mark a View method as a PUT endpoint.
Equivalent to:
@route(path, methods=["PUT"], status_code=200, ... )
- fastapi_restly.views.route(path: str, **api_route_kwargs: Any) Callable[[...], Any]#
Decorator to mark a View method as an endpoint. The path and api_route_kwargs are passed into APIRouter.add_api_route(), see for example: https://fastapi.tiangolo.com/reference/apirouter/#fastapi.APIRouter.get
Endpoints methods are later added as routes to the FastAPI app using include_view()