Skip to content

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__=FormModel makes the new class a form.
  • Each field is a (type, Field(...)) pair, with the same Field() 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.