> I also still think there are a lot of bad use cases for repositories and service layers that people should avoid, but that’s a digression which should probably become its own post
As a huge proponent of the repository pattern, I'll be looking forward to this post.
I think Django is great, and by extension that Django-Ninja is too. Considering it runs Instagram it certainly scales as well, but unlike Instagram we aren't enough engineers to be able of ripping out more and more batteries while replacing them with our own specialized batteries.
> I think type hints are misguided and unpythonic, and it's my stance that they will never be supported by peewee. Python is a high-level dynamic language, peewee plays to these strengths. You couldn't implement peewee in go, it'd look completely different.
There are thirdparty stubs available though, so I wonder how well these work.
PS: I do get that Python's type system might lack the expressiveness to fully support all ORM-like functionality, but I don't think that's a reason to not even provide hints for the super simple cases like `Person.select()`.
Pretty much every time I start a project that needs a DB I just use Django. SqlAlchemy and Alembic are usually not worth dealing with.
Two words: API Reference.
Have the clinical explanation of methods exposed, with actual breakdowns of what method parameters do. List them all, don't surround it by prose. List out the options! Don't make me dive into the source to find out what I can or can't pass into a parameter!
Having to play this game of "alright I want to know how to use this API, so first I need to figure out what tutorial page _might_ use this" to find the tiny examples that should just be next to the methods I care about in the reference is really frustrating.
Documentation is for reference, tutorials are for learning, I just don’t even understand how maintainers don’t go crazy with the absolute lack of references…
And SQL Model is even worse in that regard.
Everyone talks about moving fast and being dynamic but everyone I know deep in this has lost like actual years to churning from this kind of behavior.
Deployment is as simple as `docker compose pull && docker compose up -d`.
Highly recommend.
the docs could use some love though.
i feel most of it is references [1], the "how to"s could be better.
inb4, "where pull request", i don't grok asgi or the framework nuances to be able to say how to improve on it.
I began using the standard "tutorial" style and started cringing when I saw the official template [1] place all CRUD operations in a single file (I've been doing Rails and Spring for a while before) and the way dependencies where managed... let's just say I wasn't feeling very comfortable.
Then came the SQLModel problems. The author pushes it very hard in the FastAPI docs (which imho are terrible because when I'm looking for docs I want that, documentation, not a fancy tutorial) but as an ORM (yes I know its a layer on top of SQLAlchemy) it doesn't even support polymorphic models and the community even has contributed PRs that have gone months without any review (is it even maintained anymore? I honestly can't tell).
I guess I'm the only one to blame for choosing FastAPI to build a big project but after having used it quite a lot (and also read its code because again, docs are extremely poor) I wouldn't recommend it for anything serious. Sure, if you want to build a quick CRUD then go ahead and use SQLModel and FastAPI, but keep in mind that its not built for complex applications (at least not without requiring you to write a framework on top, like I've unfortunately done).
So yeah, a big thank you to the author of this post because I will migrate to Litestar as soon as I wake up tomorrow.
It strikes me that I haven't used web frameworks a lot and never even questioned how that may not be an easy thing to do!
If you want to actually figure out how to scale FastAPI for a large-ish app, including auth, testing and all that stuff, all with modern practices, "how they do it in that repo" is probably a good way to start with.
This made it clear to me that something about the project is off.
In any case, that’s a treasure trove right there!, I actually had no idea Polar was open source, much less that it’s built on FastAPI!
It’s such a shame that the actual documentation doesn’t even scratch the surface, I would’ve saved so much time if they just included a disclaimer along the lines of “Hey, this architecture we are showing here it’s only valid for toy projects, you will need much more work to build a real production system” but again, I guess I’m the only one to blame.
The main benefit from micro frameworks like FastAPI/Flask/Express.js is that you must build your own framework! You can pick the building blocks that will make your life easier, instead of relying on choices that made the maintainer life in full-fledged frameworks like Django/Laravel/RoR bearable. Of course, you'd need to be comfortable building frameworks and doing that work additionally to the domain modeling - pick the right tool for the job and all.
app
├── controllers
│ ├── task.py
│ └── user.py
├── models
│ ├── task.py
│ └── user.py
├── repositories
│ ├── task.py
│ └── user.py
└── schemas
├── extras
│ ├── current_user.py
│ ├── health.py
│ └── token.py
├── requests
│ ├── tasks.py
│ └── users.py
└── responses
├── tasks.py
└── users.py
A structure around mini apps always turns out to be more beneficial for keeping boundaries intact in the long run: apps
├── tasks
│ ├── controller.py
│ ├── models.py
│ ├── repository.py
│ ├── schemas.py
│ └── service.py
└── users
├── controller.py
├── models.py
├── repository.py
├── schemas.py
└── service.py
[0]: https://github.com/iam-abbas/FastAPI-Production-Boilerplate> Sometimes these are still required by our tools (like controllers or ORM units-of-work) but we keep our cross-slice logic sharing to a minimum.
That's exactly where you shouldn't be using it! Relying on it as dogma will result in chaos.
No it doesn't? The front page for FastAPI contains a pretty lengthy tutorial with no mention of SQLModel. The only time SQLModel gets a significant mention is on a page explaining connecting a relational DB, but it makes it clear that any DB at all can be used. Something has to be chosen for the tutorial, so it makes sense the author would choose their own.
If SQLModel isn't right for you then you're the only person to blame. I've been through that tutorial before and settled on plain old SQLAlchemy.
I've actually tried using litestar before and always been keeping an eye on it, but for a full fledged website needing forms, auth, etc. I find it hard to move away from just slightly tweaking Django for my needs - but still I feel drawn to Litestar as it's in between FastAPI and Django but still much closer to the former. I hope/believe in time I will feel comfortable migrating to Litestar for complex sites
I think I'll use LiteStar for my app now too.
Thanks for your good comment and I 2nd your thanks to the author.
I read this article but didn’t really get the sense there was anything sufficiently compelling to switch from Starlette.
Litestar of course supports old-school server-template-rendered sites, too; it even has a plugin for HTMX requests and responses. In practice, I find that the patterns that serve API endpoints so well sometimes get in the way of old-school "validate form and redirect, or re-render with errors" endpoints. In particular, Litestar has no "true" form support of its own; validation is really intended to flag inbound schema mismatch on API calls, not flag multiple individual error fields. Using `@post("/route", exception_handlers={...})` is pretty awkward for these endpoints. I'd be excited to see some better tools/DX in-the-box here.
I’ve recently converted to Golang, but I’d love to come back and do a litestar app in the future.
I think OP's arguments about FastAPI being hard to work with in a bigger codebase are exaggerated. Splitting up the routes into multiple files, each with its own route object, and then importing and building up a big hierarchy of route objects, isn't that hard, it does the job for me. Agreed that it's probably not well documented enough, how to structure a larger FastAPI codebase - but follow a mix of best practices and your personal tastes, break it up into modules, split it into specific files for constants / errors / routes / schemas / crud / etc, and you can scale up sanely.
I haven't used SQLAlchemy with FastAPI - for my day job I mainly connect to data stores for which it doesn't make sense - so maybe I'm biased, because I've avoided that pain.
(I used to be a maintainer, but it has been years since I worked on it).
I've preferred the Django ORM over SQLAlchemy, but I'm curious what others feel. I've gone so far as to use Django ORM for non-web projects as well. It takes a bit of work to extract though. If Django ORM had a better stand-alone story, I think more people would use it.
If I had to call out one thing it would be that you can't do tests without having a database there. This results in incredibly slow tests for even the simplest things. I don't need to test database persistence every time I'm testing some domain logic. So maybe then don't do fat models and "map" the data from Django models to a domain layer? Well, congrats, you've just manually implemented a data mapper ORM, which is what SQLAlchemy is.
It works well for simple CRUD stuff, which is really useful. But it very quickly becomes a mess and a big ball of mud when you start to do more complicated things. IMO a db access layer or web framework should be completely independent of domain logic, but Django makes that really difficult.
That is an issue/features in Django, depending on your view. You really don't get to do things the framework doesn't want. If you're trying to fight the ORM or any of the components in Django really, including the Django REST framework, you're going to lose and have a bad time.
There are certainly reason why you'd want to separate domain logic from the database access, but then Django isn't what you want. You're also going to miss out many of the things that makes Django easy to work with, like getting most CRUD operations for free.
SELECT \* FROM t1 LEFT JOIN t2 ON t1.id = t2.key AND t2.used_id = 213I find the prevailing model of having DB rows mapped 1:1 to objects in memory and syncing changes automatically to be much more trouble than it's worth, sadly most ORMs seem to use it.
For example, in Django I can have a User object. I want a update the user's first name:
my_user.first_name = "Joe"
my_user.save()
In SQLALchemy:
my_user.first_name = "Joe"
session.add(my_user)
session.commit()
Users can leave comments, so I want a query that aggregates comments for each user. In Django:
users = User.objects.all().prefetch_related("comments").annotate(comment_count=Count("comments"))
Each user will now have a `comment_count` property that contains the number of comments they left.
In SQLAlchemy:
session.query(User, func.count(Comment.id).label("comment_count")) .outerjoin(User.comments) .group_by(User.id) .all()
However, each User won't have the `comment_count` property. You have to manually associate them from the returned tuple.
I feel like SQLAlchemy wants to force you to do more work, whereas the Django ORM wants to provide you with the data you asked without forcing to you think about how to actually get the data from the database nor how to optimize the query. In Django, session management is done automatically, but it SQLAlchemy, you need to be aware of the session most times.
It's good to know SQL but you can use the Django ORM without knowing it. Not the same with SQLAlchemy. Could be a pro or a con depending on the situation. Definitely a pro for me because I don't like SQL.
Same here... better API IMO, just the right amount of abstraction (ActiveRecord-like has been fine for all the projects I was involved in) and plenty of escape hatches when needed.
I see someone citing Spring(yikes) elsewhere, that falls in the same category as FastAPI. You don't need Spring most of the times, a simple dependency injection library and small frameworks to handle the web routing or specific features you need are often enough (recent contenders to the throne of default app framework have the same issues).
Litestar does look great and a true web framework like Flask and Starlette. Stuff like FastAPI and SQLModel is a joke imo. Developers should be able to compose these things themselves if they want to.
For FastAPI I know that I can go to [1] and see what a good FastAPI code base looks like. These days even Airflow is on FastAPI but haven't looked at the codebase.
For me to jump on Litestar, I would like to see a reference codebase to learn best practices. Otherwise its one more framework whose quirks I have to get comfortable with.
[0] https://github.com/litestar-org/litestar-fullstack/blob/0996...
[1] https://github.com/litestar-org/litestar-fullstack/blob/0996...
monadoid•6mo ago