Django's biggest issue is their aging templating system. The `block`, `extend` and `include` style of composition is so limited when compared to the expressiveness of JSX. There are many libraries that try to solve Django's lack of composition/components, but it's all a band-aid. Today, making a relatively complex page with reusable components is fragile and verbose.
The second-biggest issue is lack of front end integration. Even just a blessed way of generating an OpenAPI file from models would go a long way. Django Ninja is a great peek at what that could look like. However, new JS frameworks go so much further.
The other big issue Django has _is_ solved by Cot (or Rust), which is cool (but not highlighted): complicated deployments. Shipping a bunch of Python files is painful. Also, Python's threading model means you really have to have Gunicorn (and usually Nginx) in front. Cot could have all that compiled into one binary.
About performance: I agree, and I'm not even trying to make performance a priority in Cot. I mean, of course, it's nice to have an actual compiled language, but I think a bigger perk in using Rust is having *a lot* of stuff checked in compile time, rather than in runtime. This is something I'm trying to make the main perk of, and it is reflected in multiple parts in Cot (templates checked at compile time, ORM that is fully aware of database schema at compile time, among many others).
About JSX: I think that's the one I'll need to explore further. In my defense, the templating system Cot currently uses (Rinja) is much more expressive and pleasant to use than Django's, but admittedly, the core concepts are very similar. This one might be difficult to address because of an ecosystem of templating engines that is pretty lacking in Rust, but I'll see what I can do to help this.
About front-end integration: that's something that will be (at least partially) addressed no later than v0.2. Django REST Framework is a pain (mostly because it's never been integrated in Django), Django Ninja is something I haven't personally used very much - good to have it mentioned so it can be a source of inspiration. Generating OpenAPI docs is something that's even mentioned in the article "Request Handler API is far from being ergonomic and there’s no automatic OpenAPI docs generation" so yeah, I'm aware of this.
Deployment is indeed something that's super nice – and a part of this is that newer Rust versions generally don't break compatibility with existing code, unlike Python. I agree this should be highlighted, thanks for suggestion!
(Disclaimer: I work on dioxus's native renderer)
Rocket routes work pretty well. I like being able to derive FromForm and have it reliably work, including nullable Option fields.
Maud is just wonderful. It's going to be hard to go back to plain HTML after getting the same logic in such cleaner syntax.
I haven't quite figured out authentication yet. Rocket has some functionality, but I might punt this up to Nginx (I'm using Nginx to proxy to Rocket). I'd like for cookies to be a little easier.
Rusqlite has not been fun. I couldn't get Rocket to compile with Rusqlite integration, so I've been manually opening the database for each request. (This is a very, very small site that I'm working on, and web dev is not my main role.) Anyways, all my queries are so verbose and have tons of seemingly-unnecessary Ok() statements and ? syntax. It's nice to map_err to Rocket's HTTP error types, although I'd like a less verbose version. Right now it feels like writing Java with long boilerplates that I'm copying for each route.
There are several reasons I don't like the existing ORMs in Rust, many of them being overly verbose, some generating unnecessary files, and having somewhat weird DSLs being the main reasons. The main reason, I think, was that none of them supports automatically generated migrations, and I absolutely loved that feature in Django. The differences between existing ORMs sound like a neat idea for another blog post, to be honest, so I'll probably do that soon!
Diesel absolutely can be used, there is no reason it can't - database support is feature flag-gated, so disabling it as as easy as adding one line in your Cargo.toml file. This, however, will obviously also disable some other features that depend on the database, such as authentication through database.
Whether building a custom ORM will be a good idea - only time will tell.
What about Django?
aside from joke, "I want every good thing about C++ but easiness of high level language" seems the norm
I know Go frameworks are usually like that. They spawn green threads and you can write HTTP handlers using simpler sync code to handle requests without worry.
Plus, it offers very little convenience for users vs just using a password manager. I realize figuring out the right bcrypt/datastore setup is kind of annoying, not to mention opening you up to liability, but it's always been worth it to me in the past.
One additional benefit to having OAuth2 support though is that you can easily set up SSO if needed (and you don't care about SAML or other SSO protocols). For me personally this will be useful for an NGO that I'm running where we have Google Workspace effectively serving as a Single Sign On server.
It definitely does - the sign-up process is much quicker with oath2.
Once you're signed up, sure.
Also, +1 for
> struct GownoApp;
I wonder how this par with something like https://loco.rs/
> And yes, there’s Loco (which, by the way, has started after the idea for Cot was born), which is a great framework, but [...]
The golden rule for making a website / readme for any programming language, web framework (or even GUI frameworks) is to have at least one or more code samples, so people can see what coding in your framework looks like.
I'll excuse it since it's a newish project it seems. :)
On that note, I'll be keeping a close eye on this one. This is the kind of web framework I look for, batteries included.
Cot's homepage:
Instead, use scaffolding tools, that give you a head start on creating a new project, using smaller, specialized libs.
Also, don’t use an ORM. Just write that SQL. Your future self will be thankful.
I have never understood this. I've been using the ORM for twenty years now, it's saved me countless hours, and I've very rarely needed to break out of it. When I did, I just wrote an SQL query, and that was it. What's the big deal?
It sounds like you are lucky enough that you have never had an ORM generating badly optimised/n+1/over-eager queries that take down a production service. Or perhaps had to debug low level query cache issues causing unexpected problems.
I'm not advocating for plain SQL, just offering some suggestions as to why someone might want you to consider it.
I think some of the blanket "just don't" comes from people who've had to onboard to projects written by teams that didn't understand SQL, but did (sort of) know how to use an ORM, and blame the ORM for allowing those teams to commit their atrocities. But that doesn't make an ORM a bad thing in capable hands.
It's a framework that does (or at least tries) to do everything (or as much as possible), and it's good. Really, really good.
I'm in the process of upgrading an app of mine after months of abandonment, and the process is so smooth it's boring.
Also, Django's ORM is the closest thing to a perfect tool. Sure, it has some dark corners here and there, but Django's ORM has considerably improved my quality of life as a programmer. Heck, I even moved from SQLite to PostgreSQL in an old project, and all I needed to do is to change a couple of config code.
Oh, and Django is both stable and enjoys a constant pace of updates adding useful features practically at every major version.
Honestly Django has the best db migrations I have used from any language or library.
When I start a project, even if I am going to access the db from raw sql I start by modeling it in Django just because the rapid changes in data modeling allow me to not even think about it. I just have to think about what I want it to be and not about the changes to get there. Other ORMs or no ORM I am writing alter tables instead of focusing on the data model itself.
Github copilot is so good at writing CRUD db queries that it feels as easy as an ORM, but without the baggage, complexity, and the n+1 performance issues.
I would have hoped that by 2025, new projects would have moved away from ORMs entirely. They really are a useless abstraction layer that always brings tons of trouble and usually makes queries harder to write.
Looking at the first example in the docs
https://cot.rs/guide/latest/db-models/#retrieving-models
let link = query!(Link, $slug == LimitedString::new("cot").unwrap()).get(request.db()).await?;
I really don't get the point, and that'll certainly get worse with any somewhat non-trivial query.Why go through all the trouble of reinventing a new DSL when the SQL equivalent would be so much cleaner?
SELECT * FROM link WHERE slug = 'cot';
class Account < ApplicationRecord
scope :active, -> { where.not(active_at: nil) }
belongs_to :user
end
class User < ApplicationRecord
scope :born_before, ->(born_on) { where(birthdate: born_on) }
end
active_users_with_birthdays_today = Account.active.joins(:user).merge(User.born_before(Date.today))
Contrived, of course, but it's not hard to see how you can use these sorts of things to build up record sorting, filtering, etc. Doing this by hand wouldn't be very fun.How are you canonically storing these predicates in code to reuse over 5-10 queries?
If you have a complex predicate that defines a set of rows, and you use that set in many different queries, are you rewriting it each time?
Maybe I do, maybe I don't. It depends. Most likely I won't, unless it's used in like 80 % or more of queries and the problem domain guarantees that it will basically never change and if it does it will for sure, absolutely, change everywhere at once.
I like easily testable SQL queries that are easy to read, right there in the code. No need to execute anything to get to the SQL that would execute in the database. 'But then I need to write thousands of queries?!' Yes, you do, and you'll have a chill and easy time whenever they change, and they will if your software gets use and your data grows. Because you can just search/replace on the SQL text, and don't need to figure out every place some mutilated piece might get called from and probably get it wrong a few times or need to figure out how to split it into two or more fragments.
In some cases you can figure out a robust way to generate SQL but it's rare, it mostly comes up in one-off scenarios.
Especially if you are defining types anyways to extract the data from the sql into.
In addition to that, over the years of writing web services, I always found raw queries much less maintainable. The ORM immediately tells you that you messed up your refactoring, whether it is just renaming a column, or removing a table completely.
Pretty much every ORM (including the one in Cot) also allows you to write your own custom queries if the abstractions are not enough, so there's always this fallback option.
Well sqlx checks at compile time your raw query if you use their macro, at the expense of increased compile times.
Yeah SQL is extremely simple to write, that isn’t really the problem ORMs solve for me, but rather they solve composability and reuse of queries.
I think there is a similar vein of people crying about sites not using 100% vanilla js without a framework. They are missing the point or don’t have enough experience with the actual problems the abstractions solve.
“SQL strings are one of those things that make sense for really tiny projects but fail to scale once complexity settles in“
Large projects require reuse, composability and easy refactoring. All things ORMs excel at.
On a small code base it is easy to rename a column or add a column, etc.
On a large code base with already 100s of queries using that table, without an ORM it isn’t as straightforward to update all references and ensure that ever place consuming that table has the new column info.
In my experience, the way to get the best of both worlds is to use a query builder as opposed to a full ORM.
Never had an issue with Django on a large project at a previous $8b startup whose code base went over several major data refactors.
In fact Django’s excellent migrations was specially called out for the reason for our confidence in making large DB refactors.
I use ORM query interfaces 80% of the time, and for performance critical queries I can use direct SQL. But the query sanitization, smart preloading and performance checks, schema management and migration tools they often provide, and type checks / hints are really nice features of ORMs.
Furthermore, ORMs are ESPECIALLY useful in teams where you have more junior devs who need these guardrails.
I think the issue here is trying to reinvent a new ORM.
Haskell and Elixir, etc all have ORMs (or rather ecto calls itself a data mapper but functionally it is 1:1 analogous to an ORM in any other language)
When using an ORM you already have to be good at both for any nontrivial query.
I actually find myself on crosspath where I did start with just SQL but now the database has grown a lot and it is just too much effort to keep writing queries as features pile up. Switching to ORM in one take would be nearly impossible but probably it could work as a step-by-step process, so have both SQL and ORM. Still thinking about this.
Also, people like ORMs. Type safety is nice too without having to map manually. Sqlx is also great
Don't you get type safety anyway with parameterised parameters?
Using Django's ORM, that would simply be: link=Link.objects.get(slug="cot")
It'd still be very readable and manageable even for complex queries.
Is there one framework that stands out from the rest from an "investment risk" perspective? In other words, if my company is going to choose a framework to build a website, which one has the lowest odds of burning me by becoming abandoned or unsupported?
My go to is Axum + sqlx most of the time.
…like, a lot.
I thiiiink, fundamentally, it’s a harder-than-it-looks problem space and if you come out with something that’s rough and broken, it never gains enough critical mass for it to become self sustaining.
What’s the “pitch”? It’s can’t be “Django but for rust but it’s kind of not ready yet”, bluntly.
So it needs to have some outstanding feature or accumulation of features that let it stand out from the other 30 rust web frameworks. Is there something here?
You really need to call out the “why another rust web framework” in more than just terms of ambition, imo.
The main selling point for now is the admin panel and the custom ORM that handles automatic migration generation. There are a lot of finer differences as well, and I'll add a comparison table soon since that's something I'm (expectedly) getting asked about quite frequently.
no thank you. if you like it good for you, for me this looks worse than
Body body = BodyFactory.newInstance(BodyConfiguration.OK)
which is still SHORTHER and less cancer