Skip to main content

Module viewset

Module viewset 

Source
Expand description

DRF-style ModelViewSet — five REST endpoints for any Model table in ~5 lines. See viewset::ViewSet.

v0.38 — fully tri-dialect. Internal queries route through select_rows_as_json + insert_returning_pool etc., so the same ViewSet body runs on PG / MySQL / SQLite. v0.45 — the .serializer() render extension is tri-dialect too: it fetches typed Vec<S::Model> via select_rows_pool_with_related (which decodes on every backend) and renders list / retrieve / create responses through S::from_model, so the serializer’s shape applies on PG, MySQL and SQLite.

The router(prefix, &PgPool) (static-pool) entry point keeps its PG-typed pool arg for source-compat; tenant_router(prefix) works on every dialect via the generic Tenant.pool() path (the latter is #[cfg(feature = "tenancy")]-gated inside the module; the static-pool CRUD ViewSet needs only admin — the feature that pulls axum into the dep graph). Available under either admin or tenancy so the fullstack template (admin, no tenancy) gets the CRUD ViewSet while tenant projects keep the tenant_router path. Django REST Framework–style router viewsets.

A ViewSet wires five standard REST endpoints for any Model table in ~5 lines. No hand-written handlers, no SQL, no repetition.

§Quick start

use rustango::viewset::ViewSet;

// In your router setup:
let posts_router = ViewSet::for_model(Post::SCHEMA)
    .fields(&["id", "title", "body", "author_id", "published_at"])
    .filter_fields(&["author_id"])
    .search_fields(&["title", "body"])
    .ordering(&[("published_at", true)])  // DESC by default
    .page_size(20)
    .router("/api/posts", pool.clone());

// Merge into your app router:
let app = Router::new().merge(posts_router);

§Endpoints

MethodPathAction
GET/api/postsList — {"count": N, "results": [...]}
POST/api/postsCreate — returns the new object
GET/api/posts/{pk}Retrieve — single object
PUT/api/posts/{pk}Update — full replace
PATCH/api/posts/{pk}Partial update — only supplied fields
DELETE/api/posts/{pk}Delete — 204 No Content

§Query parameters (list endpoint)

§Page-number pagination (default)

ParameterDefaultDescription
page11-based page number
page_sizeconfigured defaultItems per page (capped at 1000)
orderingconfigured defaultComma-separated field names, prefix - for DESC
searchFull-text search across search_fields
{field}Exact filter for any filter_fields
{field}__{lookup}Django-style lookup (gt/gte/lt/lte/ne/in/not_in/contains/icontains/startswith/istartswith/endswith/iendswith/isnull)

Response: {"count": N, "page": P, "page_size": S, "last_page": L, "results": [...]}

§Cursor pagination (opt-in)

Enable via .cursor_pagination("id") or .cursor_pagination_desc("id"). Skips the COUNT(*) query so it scales to billion-row tables.

ParameterDefaultDescription
cursorOpaque token from a previous response’s next field
page_sizeconfigured defaultItems per page (capped at 1000)
{field}Exact filter for any filter_fields

Response: {"page_size": S, "next": "<token>" \| null, "results": [...]}

§Limit/offset pagination (opt-in)

Enable via .limit_offset_pagination(). DRF-shape ?limit=&offset= windowing — handy for tables/grids that page by row offset rather than page number. Runs COUNT(*) per request (same cost as page-number).

ParameterDefaultDescription
limitconfigured defaultItems to return (capped at 1000)
offset0Rows to skip before the window
orderingconfigured defaultComma-separated field names, prefix - for DESC
searchFull-text search across search_fields
{field}Exact filter for any filter_fields

Response: {"count": N, "limit": L, "offset": O, "results": [...]}

§Permissions

Pair with RouterAuthExt on the outer router to require auth, then pass codenames to .permissions():

ViewSet::for_model(Post::SCHEMA)
    .permissions(ViewSetPerms {
        list:     vec!["post.view"],
        retrieve: vec!["post.view"],
        create:   vec!["post.add"],
        update:   vec!["post.change"],
        destroy:  vec!["post.delete"],
    })
    .router("/api/posts", pool.clone())

Structs§

ThrottleRule
A fixed-window throttle limit — at most max requests per window_secs (DRF ScopedRateThrottle shape, #1010).
ViewSet
Builder for a set of REST CRUD endpoints over a single [Model] table.
ViewSetPerms
Permission codenames required for each ViewSet action.
ViewSetThrottle
Per-action request throttles for a ViewSet (DRF throttle_classes parity, #1010). Any action left None is unthrottled.

Enums§

PaginationStyle
Pagination strategy for ViewSet list endpoints.

Traits§

ViewSetFilter
A pluggable filter backend (DRF BaseFilterBackend parity, #1010).