Use the escape hatches appropriately. Also - not turning on logging for your ORM and looking at what it generates or using an n+1 detector, linter, etc is the fault of the dev team, not the 'incompetent PM'.
Also the example declarative migration doesn't really feel declarative to me. Seems pretty... procedural? To me declarative is "describe the final state desired and I will generate/execute the diff". In practice I find migrations need backfill + biz logic sprinkled in.
> Migrations first, not schema first.
Similarly I don't think this works in the real world either. Please consider the poor junior dev who checks out the code base for the first time and tries to run migrations and then seed data.
The best practice has, imo, long been to load a schema file which represents what the db should be at the head of a branch and then load up your seeds. Migrations are to catch your team and live environments up. They occasionally get nuked from the codebase as everyone reconciles their environment.
> And the problem with portability is it comes at the cost of specificity. I don’t want a database access tool, I want a Postgres access tool. I want it to expose Postgres’ power user features as first-class features,
I don't know about Python based ORMs but ActiveRecord does this.