[1] https://sqlc.dev/ [2] https://nackjicholson.github.io/aiosql/
They are useful in and of themselves as internal business/domain objects, though. For a lot of cases I prefer lighter weight dataclasses that have less ceremony and runtime slowdown with the validation layer, but we use Pydantic models all over the place to guarantee and establish contracts for objects flowing thru our system, irrespective of external facing API layer.
With proper DRY, you shouldn't need to repeat the types, docstrings and validation rules. You should be able to say "these fields from user go on its default presenter, there are two other presenters with extra fields" without having to repeat all that info. I have a vague memory that Django Rest Framework does something of the sort.
This feels hard to express in modern type systems though. Perhaps the craziness that is Zod and Typescript could do it, but probably not Python.
The ontology of your persistence layer should be entirely uncoupled from that of your API, which must accommodate an external client.
In theory, anyway.
Raw sql -> eh, I don't have the patience Raw sql w type hints -> better, I at least get a compilation error when I do something wrong, and preferably a suggestion ORM -> this usually introduces it's own abstraction that needs it's own maintenance, but at least it's more code-oriented.
Yes, SQL is an awesome solution to querying DB's, hence I prefer option 2
Big fan of FastAPI but I think SQLModel leads to the wrong mental model that somehow db model and api schema are the same.
Therefore I insist on using SQLAlchemy for db models and pydantic for api schemas as a mental boundary.
a) you somehow actually have a "system of record", so modelling something in a very CRUD way makes sense, but, on the other hand, who the hell ends up building so many system of record systems in the first place to need those kinds of tools and frameworks?
b) you pretend your system is somehow a system of record when it isn't and modelling everything as CRUD makes it a uniform ball of mud. I don't understand what is so important that you can uniformly "CRUD" a bunch of objects? The three most important parts of an API, making it easy to use it right, hard to use it wrong, and easy to figure out the intent behind how your system is meant to be used, are lost that way.
c) you leak your API to your database, or your database to your API, compromising both, so both sucks.
I for one don't want to write in a low level assembly language, and shouldn't have to in 2026. Yet, SQL still feels like one.
I've written a lot of one off products using an ORM, and I don't regret any of the time savings from doing so. When and if I make $5-50M a year on a shipped product, okay, maybe I'll think about optimizing. And then I'll hire an expert while I galavant around europe.
The problem with ORMs is that they usually give you a wrong abstraction. They map poorly on how a relational database works, and what it is capable of. But the cost of it is usually poor performance, rarely it's obvious bugs. So it's really easy to get started to use; when it starts costing you, you can optimize the few most critical paths, and just pay more and more for the DB. This looks like an okay deal for the industry, it seems.
Suppose an API GET /users/:username call returns a "User" type. If returns the the same type as in your database, wouldn't you also get their password hash as well with that request? How do coupled frameworks deal with this?