API Reference
This page contains the complete API reference for Starlette Templates.
TemplateRouter
TemplateRouter(
*,
directory: PathLike | None = None,
extensions: list[str] | None = None,
index_files: list[str] | None = None,
check_dir: bool = True,
follow_symlink: bool = False,
cache_max_age: int = 3600,
gzip_min_size: int = 500,
context_processors: list[
Callable[[Request], Awaitable[dict[str, Any]]]
| Route
]
| None = None,
jinja_env: Environment | None = None,
debug: bool = False,
error_handler: Callable[
[Request, Exception], Awaitable[Response]
]
| None = None,
)
ASGI app for routing HTTP requests to Jinja2 templates with automatic resolution.
Routes incoming requests to templates with Jinja2 rendering, HTTP caching, gzip compression, and automatic file resolution (extension fallbacks, index files).
Architecture with two modes of operation: The system supports two distinct operational modes. When initialized with a directory parameter, it uses filesystem lookups to find templates through direct file access with stat and permissions checking, which is useful when templates are in a known directory. Alternatively, when initialized without a directory parameter (directory=None), it uses jinja_env loaders such as PackageLoader or FileSystemLoader, allowing templates to be served from locations defined in JinjaMiddleware, providing a single source of truth for template locations without configuration duplication.
Flow
- JinjaMiddleware defines template loaders
- Mount TemplateRouter() without directory parameter
- Request comes in: /forms
- TemplateRouter.get_response() called
- Delegates to render_template_from_loaders()
- Gets jinja_env from request.state
- Tries candidates: forms.html, forms.htm, etc.
- Finds template using jinja_env.loader.get_source()
- Renders template with context {"request": request}
- Returns ContentResponse with caching headers
Context processors are callables that accept a Request and return a dict of additional context variables to be merged into the template context.
Parameters:
-
directory(PathLike | None, default:None) –Optional path to templates directory (None = use jinja_env loaders)
-
extensions(list[str] | None, default:None) –List of allowed file extensions (default: [".html", ".htm", ".jinja", ".jinja2"])
-
index_files(list[str] | None, default:None) –List of index filenames to search for (default: ["index.html", "index.htm"])
-
check_dir(bool, default:True) –Whether to check if directory exists on init
-
follow_symlink(bool, default:False) –Whether to follow symlinks in directory
-
cache_max_age(int, default:3600) –Max age for HTTP caching (in seconds)
-
gzip_min_size(int, default:500) –Minimum size (in bytes) to apply gzip compression
-
context_processors(list[Callable[[Request], Awaitable[dict[str, Any]]] | Route] | None, default:None) –List of async callables to add to template context
-
jinja_env(Environment | None, default:None) –Optional Jinja2 Environment (falls back to request.state.jinja_env)
-
debug(bool, default:False) –Whether to enable debug mode (shows detailed error pages)
-
error_handler(Callable[[Request, Exception], Awaitable[Response]] | None, default:None) –Callable to handle exceptions and return custom responses (uses built-in handler if None)
Example
app = Starlette(
routes=[
# Override specific paths, like / which would map to index.html
Route("/", homepage, name="home"),
# Catch-all for templates
Mount("/", TemplateRouter()),
],
middleware=[
Middleware(
JinjaMiddleware,
template_loaders=[PackageLoader("myapp", "templates")]
)
]
)
StaticFiles
StaticFiles(
*,
directories: List[PathLike] | None = None,
packages: list[str | tuple[str, str]] | None = None,
html: bool = False,
check_dir: bool = True,
follow_symlink: bool = False,
)
Enhanced StaticFiles with gzip compression, caching, and multi-directory support.
Features: - Automatic gzip handling for .gz files with proper Content-Encoding headers - Strong HTTP caching (ETag, Cache-Control, Last-Modified) - Multi-directory fallback support (searches directories in priority order)
When a .gz file is requested directly, this class automatically: 1. Strips the .gz extension from the Content-Type detection 2. Sets Content-Encoding: gzip header 3. Adds Vary: Accept-Encoding header 4. Adds strong caching headers (Cache-Control: public, max-age=31536000, immutable)
When multiple directories are provided, files are searched in priority order, allowing application static files to override framework static files.
Parameters:
-
directories(List[PathLike] | None, default:None) –Directory paths to search (in priority order)
-
packages(list[str | tuple[str, str]] | None, default:None) –Package resources to serve
-
html(bool, default:False) –Enable HTML mode
-
check_dir(bool, default:True) –Whether to check if directories exist on initialization
-
follow_symlink(bool, default:False) –Whether to follow symbolic links
Example with single directory
static = StaticFiles(directories=["static"])
Example with multiple directories (priority-based override):
static = StaticFiles(
directories=[Path("app/static"), Path("framework/static")],
packages=[("myapp", "static")],
)
Example serving pre-compressed files
<link rel="stylesheet" href="{{ url_for('static', path='vendor/bootstrap.css.gz') }}">
The browser receives: - Content-Type: text/css - Content-Encoding: gzip - Cache-Control: public, max-age=31536000, immutable - And automatically decompresses the content
TemplateResponse
TemplateResponse(
template_name: str,
context: dict[str, Any] | None = None,
status_code: int = 200,
headers: Mapping[str, str] | None = None,
media_type: str | None = None,
background: Any = None,
)
HTMLResponse subclass that renders Jinja2 templates.
This class provides a convenient way to render Jinja2 templates from route handlers without manually accessing the Jinja2 environment.
The template will have access to standard context variables:
- request: The Starlette Request object
- url_for: Function to generate URLs for named routes
- absurl: Function to generate absolute URLs
- base_url: The base URL of the application
- url: Function to build full URLs from paths
- jsonify: Function to serialize data to JSON for embedding in HTML
- Plus any custom context variables provided
Parameters:
-
template_name(str) –The name of the Jinja2 template to render
-
request–The Starlette Request object (required for accessing app's Jinja2 env)
-
context(dict[str, Any] | None, default:None) –The context data to pass to the template
-
status_code(int, default:200) –The HTTP status code for the response
-
headers(Mapping[str, str] | None, default:None) –Additional headers for the response
-
media_type(str | None, default:None) –The media type for the response
-
background(Any, default:None) –A background task to run after the response is sent
Example
from starlette_templates import Application, TemplateResponse, route, model_from_request
from starlette.requests import Request
from pydantic import BaseModel
class UserModel(BaseModel):
id: int
name: str
@route("/users/{user_id}")
async def user_profile(request: Request) -> TemplateResponse:
user = model_from_request(request, UserModel)
return TemplateResponse(
"user_profile.html",
context={"user": user},
)
app = Application(
routes=[user_profile],
package_name="myapp",
)
JinjaMiddleware
JinjaMiddleware(
app: ASGIApp,
*,
state_key: str = "jinja_env",
include_websocket: bool = True,
template_loaders: list[
Union[PackageLoader, FileSystemLoader]
]
| None = None,
include_default_loader: bool = True,
extra_components: ModuleType
| type[ComponentModel]
| Sequence[ModuleType | type[ComponentModel]]
| None = None,
jinja_globals: dict[str, Any] | None = None,
jinja_filters: dict[str, Callable] | None = None,
)
Middleware to inject Jinja2 environment into request state.
This middleware creates a Jinja2 environment with the provided template loaders and makes it available in the request scope under a specified key, by default "jinja_env". This allows downstream components to access the Jinja2 environment for template rendering.
Parameters:
-
app(ASGIApp) –The ASGI application
-
state_key(str, default:'jinja_env') –The key under which to store the Jinja2 environment in request state
-
include_websocket(bool, default:True) –Whether to include WebSocket connections for Jinja2 env injection
-
template_loaders(list[Union[PackageLoader, FileSystemLoader]] | None, default:None) –List of Jinja2 template loaders to configure the environment.
-
include_default_loader(bool, default:True) –Include the default PackageLoader for "starlette_templates"
-
component_modules–Optional module, ComponentModel class, or sequence of either to auto-register components from. Can be a single module, a single ComponentModel class, or a list containing any mix of modules and ComponentModel classes.
Example
from starlette.applications import Starlette
from starlette_templates.middleware import JinjaMiddleware
from jinja2 import PackageLoader, FileSystemLoader
from myapp import custom_components # A module with custom components
from myapp.components import CustomButton, CustomCard # Individual component classes
app = Starlette()
app.add_middleware(
JinjaMiddleware,
template_loaders=[
PackageLoader("myapp", "templates"),
FileSystemLoader("custom/templates"),
],
include_default_loader=True,
# Can pass a single module, a single component, or a list of either
component_modules=[custom_components, CustomButton, CustomCard],
)
FormModel
FormModel(**data)
Base class for form models with rendering capabilities.
Attributes:
-
model_config–Configuration for form rendering and behavior
Example
Define a form model by inheriting from FormModel and using form field helpers:
import datetime
from starlette_templates.forms import FormModel, SelectField, DateField, SubmitButtonField
class Filters(FormModel):
storefront: str = SelectField(
default="ww",
choices={"ww": "Worldwide", "us": "United States"},
label="Storefront",
)
start_date: datetime.date = DateField(
default_factory=lambda: datetime.date.today(),
label="Start Date",
)
submit: str = SubmitButtonField(text="Submit")
Add forms to a specific template using TemplateResponse
async def overview(request: Request) -> TemplateResponse:
form = await Filters.from_request(request)
return TemplateResponse("overview.html", {"form": form})
app = Starlette(routes=[
Route("/overview", overview, methods=["GET", "POST"], name="overview")
])
Add forms to all templates using context_processors parameter of TemplateRouter
async def form_context_processor(request: Request) -> dict:
form = await Filters.from_request(request)
return {"form": form}
app = Starlette(
routes=[
Mount("/", TemplateRouter(
context_processors=[form_context_processor],
)),
],
middleware=[Middleware(Jinja2TemplatesMiddleware)],
)
Or assign forms to specific routes using Route in context_processors
app = Starlette(
routes=[
Route(
"/",
TemplateRouter(
context_processors=[
# Only add form to /search route templates
Route("/search", form_context_processor)
],
),
),
],
middleware=[Middleware(Jinja2TemplatesMiddleware)],
)
Methods:
-
from_request–Create form instance from request data.
-
is_valid–Check if form has no validation errors. If request is provided,
-
render–Render a specific field in HTML. This is a Jinja2 template method.
-
has_errors–Check if form has validation errors. If name is provided, checks for errors on that specific field.
-
get_field_error–Get validation error message for a specific field, if any.
-
get_error_banner_text–Get the error banner text from form config. This is text that can be displayed
-
model_dump–Override model_dump to exclude fields marked with exclude_from_dump.
-
__call__–Render the entire form. Alias for render_form().
from_request
async
classmethod
from_request(
request: Request, raise_on_error: bool = True
) -> FormModel
Create form instance from request data.
This class method parses data from the request (path params, query params, form data, and JSON body) and
validates it against the form model and returns an instance of the form model. If validation errors occur,
they are either raised as ValidationError or captured in the instance based on the raise_on_error flag.
If a field with the same name appears in multiple sources, the precedence is as follows: path params < query params < form data < JSON body. For example, if a field is present in both query params and form data, the value from form data will be used.
Use the .is_valid() method on the returned instance to check if the form data is valid when raise_on_error is False.
Parameters:
-
request(Request) –Starlette Request object
-
raise_on_error(bool, default:True) –If True, raises ValidationError. If False, captures errors in instance.
Returns:
-
FormModel–FormModel instance (with errors if raise_on_error=False)
is_valid
is_valid(request: Request | None = None) -> bool
Check if form has no validation errors. If request is provided, checks for both HTTP method and field errors to determine validity.
If request is provided, the form is only considered valid if the request method is
the same as the form's configured method (default: POST) and there are no field errors.
This means is_valid() will return False for GET requests even if there are no field errors
and will only return True for requests with the correct method and no field errors, which is
the typical behavior for form submissions.
Parameters:
-
request(Request | None, default:None) –Starlette Request object (optional)
Returns:
-
bool–True if form is valid, False otherwise
Example
async def search_page(request: Request):
form = await SearchForm.from_request(request)
if form.is_valid(request):
# Process valid form submission
...
return TemplateResponse("search.html", {"form": form})
render
async
render(
ctx: Context,
field_name: str,
request: Request | None = None,
) -> Markup
Render a specific field in HTML. This is a Jinja2 template method.
This calls the component's render method with appropriate parameters defined in the form.
If the request parameter is not provided, it will attempt to get it from the template context. If the request is still not found, an error will be raised.
Parameters:
-
ctx(Context) –Jinja2 context
-
field_name(str) –Name of the field to render
-
request(Request | None, default:None) –Starlette request object
Returns:
-
Markup–Markup of the rendered component HTML
Example
In a Jinja2 templates, use sync or async to render the field:
{{ form.render('start_date', request) }}
{{ await form.render('start_date', request) }}
You can also omit the request parameter if the template context has a request variable:
{{ form.render('start_date') }}
Raises:
-
ValueError–If the request object is not provided or found in context
-
ValueError–If the field name is not found in the form
-
ValueError–If the field does not have a component_cls defined
has_errors
has_errors(name: str | None = None) -> bool
Check if form has validation errors. If name is provided, checks for errors on that specific field.
Parameters:
-
name(str | None, default:None) –Name of the field to check for errors (optional)
Returns:
-
bool–True if there are validation errors, False otherwise
Example
if form.has_errors():
print("Form has validation errors")
if form.has_errors('email'):
print("Email field has a validation error")
You can also use this in Jinja2 templates:
{% if form.has_errors() %}
<div class="error-banner">{{ form.get_error_banner_text() }}</div>
{% endif %}
{% if form.has_errors('email') %}
<div class="field-error">{{ form.get_field_error('email') }}</div>
{% endif %}
get_field_error
get_field_error(
name: str, default: str | None = None
) -> str | None
Get validation error message for a specific field, if any.
Parameters:
-
name(str) –Name of the field
-
default(str | None, default:None) –Default value to return if no error exists for the field
Returns:
-
str | None–The error message for the field, or the default value if no error exists
Example
error_message = form.get_field_error('email', default='No error')
get_error_banner_text
get_error_banner_text() -> str
Get the error banner text from form config. This is text that can be displayed at the top of the form when there are validation errors.
model_dump
model_dump(**kwargs) -> dict[str, Any]
Override model_dump to exclude fields marked with exclude_from_dump.
__call__
async
__call__(
ctx: Context,
request: Request | None = None,
*,
id: str | None = None,
action: str | None = None,
method: str | None = None,
enctype: str | None = None,
classes: list[str] | None = None,
novalidate: bool = False,
) -> Markup
Render the entire form. Alias for render_form().
Example
{{ form() }}
{{ form(action='/submit', classes=['my-form'], enctype='multipart/form-data') }}
TextField
TextField(
default: Any = PydanticUndefined,
*,
min_length: int | None = None,
max_length: int | None = None,
regex: str | None = None,
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
label: Any = PydanticUndefined,
title: str = PydanticUndefined,
placeholder: str = PydanticUndefined,
description: str = PydanticUndefined,
required: bool = False,
hidden: bool = False,
disabled: bool = False,
readonly: bool = False,
col_class: str | None = None,
**kwargs: Any,
) -> Any
Create a string form field with validation and formatting options.
Parameters:
-
default(Any, default:PydanticUndefined) –Default value for the field
-
min_length(int | None, default:None) –Minimum length validation
-
max_length(int | None, default:None) –Maximum length validation
-
regex(str | None, default:None) –Regular expression pattern for validation
-
name(Any, default:PydanticUndefined) –Field name attribute
-
id(Any, default:PydanticUndefined) –Field id attribute
-
label(Any, default:PydanticUndefined) –Field label for display
-
title(str, default:PydanticUndefined) –Field title
-
placeholder(str, default:PydanticUndefined) –Placeholder text for input
-
description(str, default:PydanticUndefined) –Field description
-
required(bool, default:False) –Whether field is required
-
hidden(bool, default:False) –Whether field is hidden
-
disabled(bool, default:False) –Whether field is disabled
-
readonly(bool, default:False) –Whether field is readonly
-
col_class(str | None, default:None) –Bootstrap column class for horizontal layout (e.g., "col-md-4")
-
**kwargs(Any, default:{}) –Additional field attributes
Returns:
-
Any–A Pydantic Field configured for string validation
TextAreaField
TextAreaField(
default: Any = PydanticUndefined,
*,
min_length: int | None = None,
max_length: int | None = None,
rows: int = 3,
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
label: Any = PydanticUndefined,
title: str = PydanticUndefined,
placeholder: str = PydanticUndefined,
description: str = PydanticUndefined,
required: bool = False,
disabled: bool = False,
readonly: bool = False,
**kwargs: Any,
) -> Any
Create a textarea form field for multi-line text input.
Parameters:
-
default(Any, default:PydanticUndefined) –Default value for the field
-
min_length(int | None, default:None) –Minimum length validation
-
max_length(int | None, default:None) –Maximum length validation
-
rows(int, default:3) –Number of rows for textarea
-
name(Any, default:PydanticUndefined) –Field name attribute
-
id(Any, default:PydanticUndefined) –Field id attribute
-
label(Any, default:PydanticUndefined) –Field label for display
-
title(str, default:PydanticUndefined) –Field title
-
placeholder(str, default:PydanticUndefined) –Placeholder text for textarea
-
description(str, default:PydanticUndefined) –Field description
-
required(bool, default:False) –Whether field is required
-
disabled(bool, default:False) –Whether field is disabled
-
readonly(bool, default:False) –Whether field is readonly
-
**kwargs(Any, default:{}) –Additional field attributes
Returns:
-
Any–A Pydantic Field configured for textarea input
EmailField
EmailField(
default: Any = PydanticUndefined,
*,
max_length: int | None = None,
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
label: Any = PydanticUndefined,
title: str = PydanticUndefined,
placeholder: str = PydanticUndefined,
description: str = PydanticUndefined,
required: bool = False,
hidden: bool = False,
disabled: bool = False,
readonly: bool = False,
**kwargs: Any,
) -> Any
Create an email form field with email validation.
Parameters:
-
default(Any, default:PydanticUndefined) –Default value for the field
-
max_length(int | None, default:None) –Maximum length validation
-
name(Any, default:PydanticUndefined) –Field name attribute
-
id(Any, default:PydanticUndefined) –Field id attribute
-
label(Any, default:PydanticUndefined) –Field label for display
-
title(str, default:PydanticUndefined) –Field title
-
placeholder(str, default:PydanticUndefined) –Placeholder text for input
-
description(str, default:PydanticUndefined) –Field description
-
required(bool, default:False) –Whether field is required
-
hidden(bool, default:False) –Whether field is hidden
-
disabled(bool, default:False) –Whether field is disabled
-
readonly(bool, default:False) –Whether field is readonly
-
**kwargs(Any, default:{}) –Additional field attributes
Returns:
-
Any–A Pydantic Field configured for email validation
IntegerField
IntegerField(
default: Any = PydanticUndefined,
*,
gt: int | None = None,
ge: int | None = None,
lt: int | None = None,
le: int | None = None,
multiple_of: int | None = None,
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
label: Any = PydanticUndefined,
title: str = PydanticUndefined,
placeholder: str = PydanticUndefined,
description: str = PydanticUndefined,
required: bool = False,
hidden: bool = False,
disabled: bool = False,
readonly: bool = False,
**kwargs: Any,
) -> Any
Create an integer form field with numeric validation options.
Parameters:
-
default(Any, default:PydanticUndefined) –Default value for the field
-
gt(int | None, default:None) –Greater than validation
-
ge(int | None, default:None) –Greater than or equal validation
-
lt(int | None, default:None) –Less than validation
-
le(int | None, default:None) –Less than or equal validation
-
multiple_of(int | None, default:None) –Multiple of validation
-
name(Any, default:PydanticUndefined) –Field name attribute
-
id(Any, default:PydanticUndefined) –Field id attribute
-
label(Any, default:PydanticUndefined) –Field label for display
-
title(str, default:PydanticUndefined) –Field title
-
placeholder(str, default:PydanticUndefined) –Placeholder text for input
-
description(str, default:PydanticUndefined) –Field description
-
required(bool, default:False) –Whether field is required
-
hidden(bool, default:False) –Whether field is hidden
-
disabled(bool, default:False) –Whether field is disabled
-
readonly(bool, default:False) –Whether field is readonly
-
**kwargs(Any, default:{}) –Additional field attributes
Returns:
-
Any–A Pydantic Field configured for integer validation
FloatField
FloatField(
default: Any = PydanticUndefined,
*,
gt: float | None = None,
ge: float | None = None,
lt: float | None = None,
le: float | None = None,
multiple_of: float | None = None,
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
label: Any = PydanticUndefined,
title: str = PydanticUndefined,
placeholder: str = PydanticUndefined,
description: str = PydanticUndefined,
required: bool = False,
hidden: bool = False,
disabled: bool = False,
readonly: bool = False,
**kwargs: Any,
) -> Any
Create a float form field with numeric validation options.
Parameters:
-
default(Any, default:PydanticUndefined) –Default value for the field
-
gt(float | None, default:None) –Greater than validation
-
ge(float | None, default:None) –Greater than or equal validation
-
lt(float | None, default:None) –Less than validation
-
le(float | None, default:None) –Less than or equal validation
-
multiple_of(float | None, default:None) –Multiple of validation
-
name(Any, default:PydanticUndefined) –Field name attribute
-
id(Any, default:PydanticUndefined) –Field id attribute
-
label(Any, default:PydanticUndefined) –Field label for display
-
title(str, default:PydanticUndefined) –Field title
-
placeholder(str, default:PydanticUndefined) –Placeholder text for input
-
description(str, default:PydanticUndefined) –Field description
-
required(bool, default:False) –Whether field is required
-
hidden(bool, default:False) –Whether field is hidden
-
disabled(bool, default:False) –Whether field is disabled
-
readonly(bool, default:False) –Whether field is readonly
-
**kwargs(Any, default:{}) –Additional field attributes
Returns:
-
Any–A Pydantic Field configured for float validation
CheckboxField
CheckboxField(
default: Any = PydanticUndefined,
*,
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
label: Any = PydanticUndefined,
title: str = PydanticUndefined,
description: str = PydanticUndefined,
value: str = "1",
required: bool = False,
disabled: bool = False,
inline: bool = False,
**kwargs: Any,
) -> Any
Create a checkbox form field for boolean input.
Parameters:
-
default(Any, default:PydanticUndefined) –Default value for the field (True/False)
-
name(Any, default:PydanticUndefined) –Field name attribute
-
id(Any, default:PydanticUndefined) –Field id attribute
-
label(Any, default:PydanticUndefined) –Field label for display
-
title(str, default:PydanticUndefined) –Field title
-
description(str, default:PydanticUndefined) –Field description
-
value(str, default:'1') –Value submitted when checkbox is checked
-
required(bool, default:False) –Whether field is required
-
disabled(bool, default:False) –Whether field is disabled
-
inline(bool, default:False) –Whether to display inline
-
**kwargs(Any, default:{}) –Additional field attributes
Returns:
-
Any–A Pydantic Field configured for checkbox input
SelectField
SelectField(
default: Any = PydanticUndefined,
default_factory: Callable[[], Any]
| None = PydanticUndefined,
*,
choices: Dict[Any, str]
| List[Any]
| List[Choice]
| None = None,
choices_factory: Callable[
[], Dict[Any, str] | List[Any] | List[Choice]
]
| None = None,
multiple: bool = False,
size: int | None = None,
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
label: Any = PydanticUndefined,
title: str = PydanticUndefined,
placeholder: str = PydanticUndefined,
required: bool = False,
description: str = PydanticUndefined,
disabled: bool = False,
search_enabled: bool = True,
search_placeholder: str = "Type to search",
remove_button: bool = True,
max_item_count: int | None = None,
col_class: str | None = None,
**kwargs: Any,
) -> Any
Create a select form field with options.
Parameters:
-
default(Any, default:PydanticUndefined) –Default value for the field
-
choices(Dict[Any, str] | List[Any] | List[Choice] | None, default:None) –Dict of {value: label}, list of values where value=label, or list of Choice objects. Order is preserved in all formats.
-
choices_factory(Callable[[], Dict[Any, str] | List[Any] | List[Choice]] | None, default:None) –Callable that returns a dict, list, or list of Choice objects
-
multiple(bool, default:False) –Whether multiple selections are allowed (uses ChoicesSelect when True)
-
size(int | None, default:None) –Number of visible options (for Select component)
-
name(Any, default:PydanticUndefined) –Field name attribute
-
id(Any, default:PydanticUndefined) –Field id attribute
-
label(Any, default:PydanticUndefined) –Field label for display
-
title(str, default:PydanticUndefined) –Field title
-
placeholder(str, default:PydanticUndefined) –Placeholder text (for ChoicesSelect)
-
required(bool, default:False) –Whether field is required
-
description(str, default:PydanticUndefined) –Field description
-
hidden–Whether field is hidden
-
disabled(bool, default:False) –Whether field is disabled
-
search_enabled(bool, default:True) –Enable search functionality (for ChoicesSelect)
-
search_placeholder(str, default:'Type to search') –Search placeholder text (for ChoicesSelect)
-
remove_button(bool, default:True) –Show remove button for selected items (for ChoicesSelect)
-
max_item_count(int | None, default:None) –Max items that can be selected (for ChoicesSelect with multiple)
-
col_class(str | None, default:None) –Bootstrap column class for horizontal layout (e.g., "col-md-4")
-
**kwargs(Any, default:{}) –Additional field attributes
Returns:
-
Any–A Pydantic Field configured for select input
Example
Single select with dict choices (different value and label)
status = SelectField(
choices={"active": "Active", "inactive": "Inactive", "pending": "Pending"},
label="Status"
)
Single select with list choices (same value and label)
fruits = SelectField(
choices=["Apple", "Orange", "Banana"],
label="Fruit"
)
Single select with Choice objects
country = SelectField(
choices=[
Choice(value="us", label="United States"),
Choice(value="ca", label="Canada"),
Choice(value="uk", label="United Kingdom"),
],
label="Country"
)
Multiple select (uses ChoicesSelect component)
interests = SelectField(
choices={"sports": "Sports", "music": "Music", "reading": "Reading"},
multiple=True,
label="Interests"
)
Dynamic choices using a factory function
def get_country_choices():
return {"us": "United States", "uk": "United Kingdom", "ca": "Canada"}
country = SelectField(
choices_factory=get_country_choices,
label="Country"
)
DateField
DateField(
default: Any = PydanticUndefined,
default_factory: Callable[[], Any]
| None = PydanticUndefined,
*,
min: Any = PydanticUndefined,
max: Any = PydanticUndefined,
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
label: Any = PydanticUndefined,
title: str = PydanticUndefined,
placeholder: str = "Select date",
description: str = PydanticUndefined,
required: bool = False,
disabled: bool = False,
mode: str = "single",
enable_time: bool = False,
time_24hr: bool = True,
date_format: str = "Y-m-d",
inline: bool = False,
col_class: str | None = None,
**kwargs: Any,
) -> Any
Create a date form field with Flatpickr date picker.
This field renders using the Flatpickr date picker component with advanced date selection features.
Parameters:
-
default(Any, default:PydanticUndefined) –Default value for the field (can be date, datetime, or string)
-
default_factory(Callable[[], Any] | None, default:PydanticUndefined) –Factory function to generate default value
-
min(Any, default:PydanticUndefined) –Minimum allowed date (date, datetime, or ISO string)
-
max(Any, default:PydanticUndefined) –Maximum allowed date (date, datetime, or ISO string)
-
name(Any, default:PydanticUndefined) –Field name attribute
-
id(Any, default:PydanticUndefined) –Field id attribute
-
label(Any, default:PydanticUndefined) –Field label for display
-
title(str, default:PydanticUndefined) –Field title
-
placeholder(str, default:'Select date') –Placeholder text for input
-
description(str, default:PydanticUndefined) –Field description
-
required(bool, default:False) –Whether field is required
-
hidden–Whether field is hidden
-
disabled(bool, default:False) –Whether field is disabled
-
mode(str, default:'single') –Selection mode: "single", "multiple", or "range"
-
enable_time(bool, default:False) –Enable time picker
-
time_24hr(bool, default:True) –Use 24-hour time format
-
date_format(str, default:'Y-m-d') –Date format string (Flatpickr format)
-
inline(bool, default:False) –Display calendar inline
-
col_class(str | None, default:None) –Bootstrap column class for horizontal layout (e.g., "col-md-4")
-
**kwargs(Any, default:{}) –Additional field attributes
Returns:
-
Any–A Pydantic Field configured for date input
Example
Basic date field
birth_date = DateField(label="Birth Date", required=True)
Date field with range constraints
event_date = DateField(
label="Event Date",
min="2024-01-01",
max="2024-12-31"
)
Date field with default value
from datetime import date
appointment_date = DateField(
label="Appointment Date",
default=date.today(),
required=True
)
Date range picker
date_range = DateField(
label="Date Range",
mode="range"
)
Date and time picker
appointment = DateField(
label="Appointment",
enable_time=True,
date_format="Y-m-d H:i"
)
HiddenField
HiddenField(
default: Any = PydanticUndefined,
*,
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
title: str = PydanticUndefined,
description: str = PydanticUndefined,
**kwargs: Any,
) -> Any
Create a hidden form field for passing data without user interaction.
Parameters:
-
default(Any, default:PydanticUndefined) –Default value for the field
-
name(Any, default:PydanticUndefined) –Field name attribute
-
id(Any, default:PydanticUndefined) –Field id attribute
-
title(str, default:PydanticUndefined) –Field title
-
description(str, default:PydanticUndefined) –Field description
-
**kwargs(Any, default:{}) –Additional field attributes
Returns:
-
Any–A Pydantic Field configured for hidden input
Example
Basic hidden field
csrf_token = HiddenField(default="abc123")
Hidden field with custom name
user_id = HiddenField(default=42, name="user_id")
Hidden field that excludes from validation
session_key = HiddenField(
default="session_xyz",
exclude_from_validation=True
)
SubmitButtonField
SubmitButtonField(
text: str = "Submit",
*,
button_type: str = "submit",
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
classes: list[str] | None = None,
disabled: bool = False,
form: Any = PydanticUndefined,
formaction: Any = PydanticUndefined,
formenctype: Any = PydanticUndefined,
formmethod: Any = PydanticUndefined,
formnovalidate: bool = False,
formtarget: Any = PydanticUndefined,
col_class: str | None = None,
**kwargs: Any,
) -> Any
Create a submit button form field with customization options.
Parameters:
-
text(str, default:'Submit') –Button text/label
-
button_type(str, default:'submit') –Button type (submit, button, reset)
-
name(Any, default:PydanticUndefined) –Button name attribute
-
id(Any, default:PydanticUndefined) –Button id attribute
-
classes(list[str] | None, default:None) –CSS classes for the button
-
disabled(bool, default:False) –Whether button is disabled
-
form(Any, default:PydanticUndefined) –Form element the button is associated with
-
formaction(Any, default:PydanticUndefined) –URL where form data is sent when button is clicked
-
formenctype(Any, default:PydanticUndefined) –How form data is encoded when button is clicked
-
formmethod(Any, default:PydanticUndefined) –HTTP method when button is clicked
-
formnovalidate(bool, default:False) –Whether form validation is bypassed when button is clicked
-
formtarget(Any, default:PydanticUndefined) –Where to display response when button is clicked
-
col_class(str | None, default:None) –Bootstrap column class for horizontal layout (e.g., "col-md-4")
-
template–Jinja2 template for rendering the field
-
**kwargs(Any, default:{}) –Additional button attributes
Returns:
-
Any–A Pydantic Field configured for submit button
Example
Basic submit button
submit = SubmitButtonField("Save Changes")
Customized submit button
submit = SubmitButtonField(
text="Create Account",
classes=["btn", "btn-primary", "btn-lg"],
id="create-account-btn"
)
Button with form attributes
delete_btn = SubmitButtonField(
text="Delete",
button_type="submit",
formmethod="DELETE",
formnovalidate=True,
classes=["btn", "btn-danger"]
)
TagField
TagField(
default: Any = PydanticUndefined,
*,
separator: str = ",",
placeholder: str = "Enter tags separated by commas",
max_tags: int | None = None,
tag_pattern: str | None = None,
badge_class: str = "badge bg-primary text-white",
show_validation: bool = True,
name: Any = PydanticUndefined,
id: Any = PydanticUndefined,
label: Any = PydanticUndefined,
title: str = PydanticUndefined,
description: str = PydanticUndefined,
required: bool = False,
hidden: bool = False,
disabled: bool = False,
**kwargs: Any,
) -> Any
Create a tag input form field for comma-separated values.
This field renders as a text input with live tag visualization using Bootstrap badges. It supports tag validation, max tag limits, and custom styling.
Parameters:
-
default(Any, default:PydanticUndefined) –Default value for the field (can be list or comma-separated string)
-
separator(str, default:',') –Character used to separate tags (default: comma)
-
placeholder(str, default:'Enter tags separated by commas') –Placeholder text for the input field
-
max_tags(int | None, default:None) –Maximum number of tags allowed (None for unlimited)
-
tag_pattern(str | None, default:None) –Regex pattern for individual tag validation
-
badge_class(str, default:'badge bg-primary text-white') –Bootstrap badge CSS classes for tag display
-
show_validation(bool, default:True) –Whether to show validation styling (is-valid/is-invalid)
-
name(Any, default:PydanticUndefined) –Field name attribute
-
id(Any, default:PydanticUndefined) –Field id attribute
-
label(Any, default:PydanticUndefined) –Field label for display
-
title(str, default:PydanticUndefined) –Field title
-
description(str, default:PydanticUndefined) –Field description
-
required(bool, default:False) –Whether field is required
-
template–Jinja2 template for rendering the field
-
**kwargs(Any, default:{}) –Additional field attributes
Returns:
-
Any–A Pydantic Field configured for tag input
Example
Basic tag field
tags = TagField(label="Tags", default=["python", "javascript"])
Tag field with custom separator
keywords = TagField(
label="Keywords",
separator=";",
placeholder="Enter keywords separated by semicolons"
)
Limited tag field with custom styling
categories = TagField(
label="Categories",
max_tags=5,
badge_class="badge bg-secondary text-white",
required=True
)
Tag field without validation styling
draft_tags = TagField(
label="Draft Tags",
show_validation=False,
badge_class="badge border border-primary text-primary"
)
model_from_request
async
model_from_request(request: Request, model: Type[T]) -> T
model_from_request(
request: Request, model: None = None
) -> dict
model_from_request(
request: Request, model: Type[T] | None = None
) -> T | dict
Parse and validate request body against a Pydantic model.
Loads data from path params, query params, and request body (JSON or form), in that order, overriding earlier values. Form fields that allow multiple values (like multi-select) are handled appropriately.
This function can be used to populate a Pydantic model instance from request data, or return a dict of parameters if no model is provided.
Parameters:
-
request(Request) –Starlette Request object
-
model(Type[T] | None, default:None) –Pydantic model class to validate against (optional)
Returns:
-
T | dict–An instance of the Pydantic model if provided, otherwise a dict of parameters.
AppException
AppException(
detail: str,
status_code: int = 400,
code: ErrorCode | str | None = None,
source: ErrorSource | None = None,
meta: dict[str, Any] | None = None,
)
Base exception for all application errors with JSON:API compliance.
This exception provides structured error information that can be rendered as either JSON (for API requests) or HTML (for browser requests).
Parameters:
-
detail(str) –Human-readable description of the error
-
status_code(int, default:400) –HTTP status code (default: 400)
-
code(ErrorCode | str | None, default:None) –Machine-readable error code
-
source(ErrorSource | None, default:None) –Location of the error (JSON pointer, parameter name, etc.)
-
meta(dict[str, Any] | None, default:None) –Additional metadata about the error
Example
raise AppException(
detail="User with email 'john@example.com' already exists",
status_code=409,
code=ErrorCode.DUPLICATE_RESOURCE,
source=ErrorSource(parameter="email"),
meta={"email": "john@example.com"}
)
ErrorCode
Error codes for API responses following JSON:API specification.
Attributes:
-
INTERNAL_ERROR–Internal server error not caused by client request.
-
INVALID_REQUEST–The request is malformed or contains invalid parameters.
-
INVALID_PARAMETER–A specific parameter in the request is invalid.
-
NOT_FOUND–The requested resource could not be found.
-
VALIDATION_ERROR–The request data failed validation checks.
-
UNAUTHORIZED–Authentication is required and has failed or not been provided.
-
FORBIDDEN–Access to the requested resource is forbidden.
-
METHOD_NOT_ALLOWED–The HTTP method used is not allowed for the requested resource.
INTERNAL_ERROR
class-attribute
instance-attribute
INTERNAL_ERROR = 'internal_error'
Internal server error not caused by client request.
INVALID_REQUEST
class-attribute
instance-attribute
INVALID_REQUEST = 'invalid_request'
The request is malformed or contains invalid parameters.
INVALID_PARAMETER
class-attribute
instance-attribute
INVALID_PARAMETER = 'invalid_parameter'
A specific parameter in the request is invalid.
NOT_FOUND
class-attribute
instance-attribute
NOT_FOUND = 'not_found'
The requested resource could not be found.
VALIDATION_ERROR
class-attribute
instance-attribute
VALIDATION_ERROR = 'validation_error'
The request data failed validation checks.
UNAUTHORIZED
class-attribute
instance-attribute
UNAUTHORIZED = 'unauthorized'
Authentication is required and has failed or not been provided.
FORBIDDEN
class-attribute
instance-attribute
FORBIDDEN = 'forbidden'
Access to the requested resource is forbidden.
METHOD_NOT_ALLOWED
class-attribute
instance-attribute
METHOD_NOT_ALLOWED = 'method_not_allowed'
The HTTP method used is not allowed for the requested resource.
ErrorSource
JSON:API error source object indicating where the error originated.
Attributes:
pointer
class-attribute
instance-attribute
pointer: str | None = None
parameter
class-attribute
instance-attribute
parameter: str | None = None
header
class-attribute
instance-attribute
header: str | None = None
context
Jinja2 context builders and custom filters for starlette_templates templates.
Functions:
-
jsonify–Convert data to a JSON string for embedding in HTML templates.
-
url_for–Generate URL for a named route.
-
url–Generate URL for a mounted application.
-
absurl–Build absolute URL from path.
-
register_jinja_globals_filters–Register global functions and filters in the Jinja2 environment.
jsonify
jsonify(data: Any, indent: int | None = None) -> Markup
Convert data to a JSON string for embedding in HTML templates.
Uses Pydantic's built-in JSON serialization to handle complex data types like datetime, Decimal, and BaseModel instances.
Parameters:
-
data(Any) –The data to serialize to JSON
Returns:
-
Markup–A Markup-safe JSON string representation of the data
url_for
url_for(
context: dict, name: str, **path_params: Any
) -> str
Generate URL for a named route.
This function uses @pass_context to access the request from the template context. The request must be added to the context by TemplateRouter or TemplateResponse.
Parameters:
-
context(dict) –Jinja2 context (automatically passed by Jinja2)
-
name(str) –Route name
-
**path_params(Any, default:{}) –Path parameters for the route
Returns:
-
str–URL path for the named route
Example
Assuming a route defined as:
async def user_profile(request: Request):
...
app = Starlette(routes=[
Route("/users/{user_id}/profile", user_profile, name="user_profile"),
])
You can generate the URL by name in a template like this:
{{ url_for('user_profile', user_id=123) }}
<!-- Outputs: 'http://example.com/users/123/profile' -->
Note
This is registered as a Jinja2 global by register_jinja_globals_filters() and can be used directly in templates without importing.
url
url(context: dict, name: str, path: str = '/') -> str
Generate URL for a mounted application.
This function builds URLs for Starlette Mount instances by name. It's a convenience wrapper around url_for specifically for mounts.
Parameters:
-
context(dict) –Jinja2 context (automatically passed by Jinja2)
-
name(str) –Mount name
-
path(str, default:'/') –Path within the mount (default: "/")
Returns:
-
str–URL path for the mounted application
Example
Assuming a mount defined as:
app = Starlette(routes=[
Mount("/static", StaticFiles(directory="static"), name="static_files"),
])
You can generate URLs for files within the mount in a template like this:
{{ url('static_files', '/css/style.css') }}
<!-- Outputs: 'http://example.com/static/css/style.css' -->
Note
For named routes, use url_for instead. This is specifically for Mount instances.
absurl
absurl(context: dict, path: str) -> str
Build absolute URL from path.
Converts a relative path to an absolute URL by combining it with the request's base URL (scheme + host).
Parameters:
-
context(dict) –Jinja2 context (automatically passed by Jinja2)
-
path(str) –URL path (relative or absolute)
Returns:
-
str–Full absolute URL with scheme and host
Example
Creates an absolute URL for the given path:
{{ absurl('/path/to/resource') }}
<!-- Outputs: 'http://example.com/path/to/resource' -->
Note
Different from url_for which uses named routes. This takes a literal path.
register_jinja_globals_filters
register_jinja_globals_filters(
jinja_env: Environment,
jinja_globals: dict[str, Any] | None = None,
jinja_filters: dict[str, Callable] | None = None,
) -> None
Register global functions and filters in the Jinja2 environment.
This function adds commonly used utilities to the Jinja2 environment so they can be accessed directly in templates without importing.
Called by JinjaMiddleware during initialization to set up the environment.
Uses setdefault to avoid overriding any custom globals that may have been set, following the same pattern as Starlette's built-in template functions.
Parameters:
-
jinja_env(Environment) –The Jinja2 Environment instance
Flow
- JinjaMiddleware creates jinja_env with template loaders
- Calls this function to register globals/filters
- Stores jinja_env in request.state.jinja_env
- Templates can use these functions: {{ url_for(...) }}, {{ data|jsonify }}, etc.
- @pass_context functions access request from context["request"]