FormBuilder.from_pydantic() generates a Bootstrap-styled form from a Pydantic model.
Pydantic v2 required
FormBuilder.from_pydantic() reads model_fields, which is the Pydantic v2 model API. Pydantic v1 models are not supported by this helper.
Naming update in v0.6.1
Starting in Faststrap v0.6.1, the preferred import is FormBuilder to avoid confusion
with FastHTML's native Form element.
v0.6.1+: from faststrap import FormBuilder
v0.6.0 and earlier: from faststrap import Form
Form remains available as a compatibility alias, but new code should prefer FormBuilder.
Import
from faststrap import FormBuilder
Basic Usage
from pydantic import BaseModel, EmailStr
class Signup(BaseModel):
email: EmailStr
age: int
marketing_opt_in: bool = False
form = FormBuilder.from_pydantic(Signup, action="/signup")
Supported Field Mapping (MVP)
str -> text input
EmailStr -> email input
int -> number input
float -> number input (step="any")
bool -> checkbox
Literal[...] -> select
Enum -> select
Options
| Parameter |
Type |
Default |
Description |
model_class |
type[Any] |
required |
Pydantic BaseModel class. |
action |
str \| None |
None |
Form submit URL. |
method |
str |
"post" |
Form method. |
include |
list[str] \| None |
None |
Include only selected fields. |
exclude |
list[str] \| None |
None |
Exclude selected fields. |
submit_label |
str |
"Submit" |
Submit button text. |
submit_variant |
str |
"primary" |
Bootstrap button variant. |
form_cls |
str |
"" |
Extra form classes. |
button_cls |
str |
"" |
Extra submit button classes. |
**kwargs |
Any |
|
Extra form attributes, including HTMX attributes. |
HTMX Submit Example
FormBuilder.from_pydantic(
Signup,
hx_post="/signup",
hx_target="#signup-result",
hx_swap="outerHTML",
submit_label="Create account",
)
Validation Flow
Use FormErrorSummary, FormGroupFromErrors, LiveValidationField, and ValidationMessage when you need server-side error rendering or live field validation. FormBuilder.from_pydantic() focuses on generating the initial Bootstrap-styled form.
Backward Compatibility
If you are maintaining a project pinned below v0.6.1, this older import still works:
from faststrap import Form
form = Form.from_pydantic(Signup, action="/signup")
API Reference
Form builder helpers.
Source code in src/faststrap/components/forms/form.py
| @beta
class FormBuilder:
"""Form builder helpers."""
@staticmethod
def from_pydantic(
model_class: type[Any],
*,
action: str | None = None,
method: str = "post",
include: list[str] | None = None,
exclude: list[str] | None = None,
submit_label: str = "Submit",
submit_variant: str = "primary",
form_cls: str = "",
button_cls: str = "",
**kwargs: Any,
) -> FTForm:
"""Generate a Bootstrap-styled form from a Pydantic model class."""
try:
pydantic_module = importlib.import_module("pydantic")
except ImportError as exc:
msg = (
"FormBuilder.from_pydantic() requires pydantic. "
"Install with `pip install pydantic`."
)
raise ImportError(msg) from exc
base_model = pydantic_module.BaseModel
if not isinstance(model_class, type) or not issubclass(model_class, base_model):
msg = "FormBuilder.from_pydantic() expects a Pydantic BaseModel class."
raise TypeError(msg)
model_fields = getattr(model_class, "model_fields", None)
if not isinstance(model_fields, dict):
msg = "Unsupported Pydantic model format."
raise TypeError(msg)
include_set = set(include or model_fields.keys())
exclude_set = set(exclude or [])
fields: list[Any] = []
for name, field_info in model_fields.items():
if name not in include_set or name in exclude_set:
continue
input_element, required = _build_field_input(name, field_info)
label = getattr(field_info, "title", None) or _pretty_label(name)
description = getattr(field_info, "description", None)
fields.append(
FormGroup(
input_element,
label=label,
help_text=description,
required=required,
)
)
fields.append(
FTButton(
submit_label,
type="submit",
cls=f"btn btn-{submit_variant} {button_cls}".strip(),
)
)
form_attrs: dict[str, Any] = {
"method": method,
"cls": f"faststrap-generated-form {form_cls}".strip(),
}
if action:
form_attrs["action"] = action
form_attrs.update(kwargs)
form_attrs = convert_attrs(form_attrs)
return FTForm(*fields, **form_attrs)
|
Generate a Bootstrap-styled form from a Pydantic model class.
Source code in src/faststrap/components/forms/form.py
| @staticmethod
def from_pydantic(
model_class: type[Any],
*,
action: str | None = None,
method: str = "post",
include: list[str] | None = None,
exclude: list[str] | None = None,
submit_label: str = "Submit",
submit_variant: str = "primary",
form_cls: str = "",
button_cls: str = "",
**kwargs: Any,
) -> FTForm:
"""Generate a Bootstrap-styled form from a Pydantic model class."""
try:
pydantic_module = importlib.import_module("pydantic")
except ImportError as exc:
msg = (
"FormBuilder.from_pydantic() requires pydantic. "
"Install with `pip install pydantic`."
)
raise ImportError(msg) from exc
base_model = pydantic_module.BaseModel
if not isinstance(model_class, type) or not issubclass(model_class, base_model):
msg = "FormBuilder.from_pydantic() expects a Pydantic BaseModel class."
raise TypeError(msg)
model_fields = getattr(model_class, "model_fields", None)
if not isinstance(model_fields, dict):
msg = "Unsupported Pydantic model format."
raise TypeError(msg)
include_set = set(include or model_fields.keys())
exclude_set = set(exclude or [])
fields: list[Any] = []
for name, field_info in model_fields.items():
if name not in include_set or name in exclude_set:
continue
input_element, required = _build_field_input(name, field_info)
label = getattr(field_info, "title", None) or _pretty_label(name)
description = getattr(field_info, "description", None)
fields.append(
FormGroup(
input_element,
label=label,
help_text=description,
required=required,
)
)
fields.append(
FTButton(
submit_label,
type="submit",
cls=f"btn btn-{submit_variant} {button_cls}".strip(),
)
)
form_attrs: dict[str, Any] = {
"method": method,
"cls": f"faststrap-generated-form {form_cls}".strip(),
}
if action:
form_attrs["action"] = action
form_attrs.update(kwargs)
form_attrs = convert_attrs(form_attrs)
return FTForm(*fields, **form_attrs)
|
Compatibility wrapper for FastHTML's native Form element.
Form(...) delegates to FastHTML's native Form so wildcard imports do
not accidentally break ordinary form markup. Form.from_pydantic() is
retained for backward compatibility with Faststrap v0.6.0 and earlier.
New code should prefer FormBuilder.from_pydantic() for generated forms.
Source code in src/faststrap/components/forms/form.py
| @beta
class Form:
"""Compatibility wrapper for FastHTML's native `Form` element.
`Form(...)` delegates to FastHTML's native `Form` so wildcard imports do
not accidentally break ordinary form markup. `Form.from_pydantic()` is
retained for backward compatibility with Faststrap v0.6.0 and earlier.
New code should prefer `FormBuilder.from_pydantic()` for generated forms.
"""
def __new__(cls, *children: Any, **kwargs: Any) -> FTForm:
return FTForm(*children, **kwargs)
@staticmethod
def from_pydantic(
model_class: type[Any],
*,
action: str | None = None,
method: str = "post",
include: list[str] | None = None,
exclude: list[str] | None = None,
submit_label: str = "Submit",
submit_variant: str = "primary",
form_cls: str = "",
button_cls: str = "",
**kwargs: Any,
) -> FTForm:
warnings.warn(
"Form.from_pydantic() is deprecated as of Faststrap v0.6.1; "
"use FormBuilder.from_pydantic() instead. "
"The Form alias remains supported for backward compatibility.",
DeprecationWarning,
stacklevel=2,
)
return FormBuilder.from_pydantic(
model_class,
action=action,
method=method,
include=include,
exclude=exclude,
submit_label=submit_label,
submit_variant=submit_variant,
form_cls=form_cls,
button_cls=button_cls,
**kwargs,
)
|