Forms Built at Runtime¶
Usually a form is a class you write. When the fields are only known while the
app runs, for example an admin screen where staff design a survey, or fields
stored in a database, build the FormModel class with Pydantic's
create_model(). The result is an ordinary FormModel: it renders,
validates and re-renders errors exactly like a class you wrote.
from pydantic import create_model
from pydantic_schemaforms import Field, FormModel, render_form_html
# Loaded from a database or a config file at runtime
FIELDS = [
{'name': 'name', 'title': 'Your name', 'ui_element': 'text', 'required': True},
{'name': 'email', 'title': 'Email', 'ui_element': 'email', 'required': True},
{'name': 'rating', 'title': 'Rating', 'ui_element': 'rating', 'required': False},
{'name': 'comments', 'title': 'Comments', 'ui_element': 'textarea', 'required': False},
]
def build_form(fields: list[dict]) -> type[FormModel]:
return create_model(
'FeedbackForm',
__base__=FormModel,
**{
spec['name']: (
str,
Field(
... if spec['required'] else '',
title=spec['title'],
ui_element=spec['ui_element'],
),
)
for spec in fields
},
)
FeedbackForm = build_form(FIELDS)
form_html = render_form_html(FeedbackForm, submit_url='/feedback')
__base__=FormModelmakes the new class a form.- Each field is a
(type, Field(...))pair, with the sameField()settings as anywhere else:title,ui_element, constraints,ui_options. ...as the default makes a field required.- Build each class once, when the definition changes, rather than on every request: Pydantic does real work to create a model.
Treat stored field definitions as untrusted input if users can edit them:
choose the type and ui_element from a list you control, rather than
passing stored strings straight through.
Coming: JSON Schema import
Building a form straight from a JSON Schema document is planned
(#235).
Until then, create_model() is the way to build a form at runtime.