I've been working with FastHTML and I have to say, I rather enjoy HTML-markup-as-objects.
It works pretty seamlessly and you get something like this:
@app.post('/part/add')
def create_part(part_number: str, name: str, description: str):
p = Part(part_number=part_number, name=name, description=description)
p.save()
return (p,
Input(placeholder="part number", id="part_number", hx_swap_oob='true'),
Input(placeholder="description", id="description", hx_swap_oob='true'),
Input(placeholder="name", id="name", hx_swap_oob='true'))
Note, I'm not using FastHTML's built-in database interface. I prefer a little less implicit than the strict FastHTML style.