Skip to main content

Module template_views

Module template_views 

Source
Expand description

Generic class-based views for HTML templates — ListView, DetailView, CreateView, UpdateView, DeleteView over #[derive(Model)] schemas, rendered with Tera. The HTML sibling of viewset. Runs on all three backends. See template_views for usage and the Tera context shape. Generic class-based views for HTML templates.

Sibling of crate::viewset for the JSON/API side. Each view is a data structure that builds a Tera-rendered axum Router over a #[derive(Model)] schema:

ViewWhat it doesTemplate default
ListViewPaginated list — ?page=N query param<table>_list.html
DetailViewSingle row by primary key — /{pk}<table>_detail.html
CreateViewGET empty form / POST insert / 303 to success_url<table>_form.html
UpdateViewGET prefilled form / POST update / 303<table>_form.html
DeleteViewGET confirm / POST delete / 303<table>_confirm_delete.html

§Quick start

ⓘ
use rustango::template_views::ListView;
use std::sync::Arc;

let mut tera = rustango::template_extensions::html_tera();
tera.add_raw_template("post_list.html", r#"
    {% for post in object_list %}
        <h2>{{ post.title }}</h2>
        <p>{{ post.body }}</p>
    {% endfor %}
    {% if has_prev %}<a href="?page={{ page - 1 }}">prev</a>{% endif %}
    {% if has_next %}<a href="?page={{ page + 1 }}">next</a>{% endif %}
"#).unwrap();

let app = ListView::for_model(Post::SCHEMA)
    .page_size(20)
    .order_by("created_at", true)   // DESC
    .router("/posts", Arc::new(tera), pool);

§Tera context

Every view stamps a consistent context shape so templates port cleanly between views:

  • object_list: Vec<Map<String, Value>> — the page’s rows as JSON (null for SQL nulls; columns named after the field’s column)
  • page: i64 — 1-indexed current page
  • page_size: i64
  • total: i64 — total matching rows across every page
  • total_pages: i64
  • has_next: bool
  • has_prev: bool

§Pool capture vs per-tenant resolution

Each view ships two router constructors:

  • .router(prefix, tera, pool) — single-tenant, captures a PgPool at mount time. Mirrors the original ViewSet::router.
  • .tenant_router(prefix, tera) — multi-tenant, resolves a per-request connection via the crate::extractors::Tenant extractor. Mirrors viewset::ViewSet::tenant_router. Available behind the combined template_views + tenancy features.

Same builder API across both flavors; pick whichever matches the project’s connection-management strategy. Templates port between them without edits.

Structs§

BulkAction
One registered bulk action. The framework ships delete_selected as a built-in when ListView::bulk_actions is enabled; user-defined actions wire in via ListView::action (static pool) or ListView::tenant_action (per-request tenant connection).
CreateView
GET <prefix>/new renders an empty form, POST <prefix>/new inserts the row and 303s to success_url.
DeleteView
Two-step delete: GET <prefix>/{pk}/delete renders a confirmation page, POST <prefix>/{pk}/delete executes the delete and 303s to success_url.
DetailView
Render a single row of M looked up by primary key.
ExtraContext
Extra template context, supplied per request through an axum Extension.
FormView
No-model CBV that renders a #[derive(Form)] form on GET, parses
ListView
Render a paginated list of rows for M.
RedirectView
No-model CBV that returns an HTTP redirect to a fixed URL. Use for canonical URL migrations (old /about-us → new /about), short links, or “click here to go there” flows. Issue #13.
TemplateView
No-model CBV that renders a Tera template with a static context. Use for about pages, terms-of-service, dashboards built from context the caller assembles up front.
UpdateView
GET <prefix>/{pk}/edit renders a form prefilled from the row; POST <prefix>/{pk}/edit updates the row and 303s to success_url.

Enums§

BulkActionHandler
Either a static-pool handler or a tenant-mode handler. Built up by the builder methods and dispatched in the matching POST handler. Mixing kinds on the same ListView doesn’t make sense (the router only mounts one handler shape), so the wrong-kind case surfaces a clear runtime error rather than corrupting the connection.

Type Aliases§

BulkActionFn
Handler closure for a bulk action mounted on the static-pool ListView::router path. Receives the captured &Pool and the parsed list of selected primary keys (already type-coerced from the form’s _selected_action strings).
BulkActionFuture
Future returned by a ListView bulk action handler. Mirrors the shape admin::AdminActionFuture uses so handlers feel consistent across the framework. Errors render as a 400 response with the supplied string in the body.
TenantBulkActionFn
Tenant-mode counterpart — runs against the per-request tenant connection from crate::extractors::Tenant::conn. Wired via ListView::tenant_action. v0.38 — PG-only by signature (takes &mut PgConnection). Sqlite/ MySQL tenants get the tri-dialect Pool-based variant TenantBulkActionPoolFn below.
TenantBulkActionPoolFn
Tri-dialect tenant-mode bulk-action handler — runs against the per-request tenant Pool from crate::extractors::Tenant::pool so the handler works on Postgres, MySQL, and SQLite tenants uniformly. Wired via ListView::tenant_action_pool.
Validator
User-supplied validation hook installed on CreateView / UpdateView via CreateView::validator / UpdateView::validator (or the Form-trait convenience CreateView::form / UpdateView::form). Runs after schema-level type coercion + max_length / min / max bounds (which the framework owns) but before the SQL INSERT/UPDATE. Returning Err(FormErrors) re-renders the form with the merged error map and a 422 status.