I'm working on a Rails and on a Django project for two different customers and I've been doing that for years now. I'd pick Rails over Django any time for every single feature.
The absolute worst Django feature is the templating language. It seems to be designed to slow down developers to the like of old time Java web apps, almost mandatory templatetags et all.
The query language is moderately bad, quite verbose (Model.objects every time) for no good reason.
The lack of common project structure means that every project is different.
There is no Capistrano to deploy. I wrote something like that myself and we have been using it for maybe 7 years.
I'm sure I could go on for a while if I keep thinking about it, but you got the gist of it.
On the Rails side, sometimes I'd like to have a talk with some of the previous developers of the Rails app, which hid some important functionality in a before save callback in a different module for no particular reason, but one can be too clever with Python too. However the language (Python) is quite dull, which can be a good or a bad thing. It's very subjective. It's a Ruby gone bad at design time to me.
> The absolute worst Django feature is the templating language. It seems to be designed to slow down developers to the like of old time Java web apps, almost mandatory templatetags et all.
They wanted to provide safe and clean templating, so they decided to force developers to write tags instead of putting logic inside templates.
I agree it's quite overkill because I still want to run code like I would with ERB or PHP sometimes instead of being forced to write a tag. But this can lead to difficult to debug templates and security problems.
> The query language is moderately bad, quite verbose (Model.objects every time) for no good reason.
The idea was to make the separation between Model and QuerySet objects obvious. When you access the objects property on the model object, you're actually accessing the QuerySet.
It seems weird because in Rails, everything is encapsulated in the model's class. But Python devs tend to prefer explicit code. In Django we also have the Manager class as an additional layer used to build QuerySets. I'd say it's just a different architecture instead of a shortcoming.
> The lack of common project structure means that every project is different.
This is a real problem but I reckon that big Rails projects aren't as easy to navigate either because most don't stick to the Rails way as soon as custom business logic is needed.
I would say that Django isn't worse than Rails. They just decided to be more strict in some places, which isn't necessarily a bad thing. In the end, you just need to work with whatever you prefer.
> > The query language is moderately bad, quite verbose (Model.objects every time) for no good reason.
> The idea was to make the separation between Model and QuerySet objects obvious. When you access the objects property on the model object, you're actually accessing the QuerySet.
> It seems weird because in Rails, everything is encapsulated in the model's class. But Python devs tend to prefer explicit code. In Django we also have the Manager class as an additional layer used to build QuerySets. I'd say it's just a different architecture instead of a shortcoming.
Also, you're supposed to enhance the models with additional functionality independent of views. Not just in the form of just adding new class or instance methods, but you can also redefine or add alternate QuerySet Managers. For example "Model.objects" could be replaced with a pre-filtered one that includes "deleted=False" and you can add "Model.deleted" for "deleted=True" and "Model.all" for the original get-everything QuerySet.
I've used them both in production enough to feel qualified to counter these, but we'd all just be arguing for our opinions. Both are excellent frameworks, with no clear standout IMO.
I will say one thing in response: we've found it approximately 10x easier to find devs having years of experience with Python than with Ruby. That's a non-trivial argument in Django's favour in our organisation.
The basics are trivial to learn but the object model and lambda style programming as well as metaprogramming (method_missing, etc) can be overwhelming for some folks to pick up quickly. I absolutely love Ruby though.
A bit off topic, but whenever Rails and templating get brought up, I have to plug my absolute favorite project out there: Phlex https://beta.phlex.fun/. It's like ViewComponents, but swap out the ERB for pure Ruby. It has been a joy to develop with.
With the addition of Phlex::Kit, it has made building out a component library pretty easy too.
RubyUI https://github.com/ruby-ui/ruby_ui does a great job of showing off how to do this.
Those kind of things used to be a lose lose proposition back at the time of haml (?) and all the yaml like templating languages. That was more than 10 years ago. The reason was that any designer that could actually do html was able to write an erb page, maybe except loops and logic, but they could understand them if a developer added them into the page later. On the other side with one of those languages, and more with phlex, only a developer could write the views so we were back to the 90s with photoshop layouts.
Furthermore your can't copy and paste examples. Think about Bootstrap components. You have to really write everything from scratch.
Agreed. The whole idea of writing html from scratch using special tags in the code makes no sense to me. It basically destroys the separation between code and design/templates.
The Rails dev says that Rails defaults are very good and so says the Django dev about the Django defaults.
The Django ORM is loved by tens, maybe hundreds of thousands of Python devs globally, and while I could raise concerns about it (for example, the async experimental capabilities fucking suck, and the core dev team is extremely slow to innovate on them on the basis that that's not "the Django way"), I've never heard anyone but a Rails dev complain that it's "too verbose".
People love it so much that they'll do atrocities like import it into Jupyter notebooks or simple scripts that should otherwise have no business in bringing in those type of dependencies. I should know because when I've felt creative and a bit naughty about doing those types of things I've found out - to my unmeasurable disappointment - that there were many other trailblazers before me to write gists, Medium articles, and almost everything every type of format short of an entire O'Reilly book on how to do it.
Wouldn't know. However, some standalone projects are attempting to replicate the same experience, check Tortoise ORM - https://github.com/tortoise/tortoise-orm.
That increases the support cost so I think the first question would be who’s going to use it. Django has a lot of value from integration and you wouldn’t get that as a stand-alone product, and the people who want to mix their own framework tend to pick SQLAlchemy. If there isn’t a clear community it’d be taking time away from things existing users want in the hopes of attracting other users, so you’d really want to make sure that demand was there.
That's curious to me honestly. I really prefer the ergonomics of Django's ORM compared to when I've had to use SQLAlchemy+Alembic in the past. I find alembic incredibly confusing and poorly documented. Not that documentation matters as much nowadays with AI
Alembic is certainly a bit of a challenge to grasp at first, especially if you want to do anything more complicated than create or alter tables. However, it does provide a great amount of flexibility if you want to implement more complex migration functionality. It allows library developers to add powerful features that would be very difficult to do with Rails/ActiveRecord or Django ORM.
FWIW I maintain the flask-audit-logger package. It allows users to maintain audit logs of specific tables using postgres triggers. Being able to create custom migration operations is really an amazing feat. The alembic docs are quite dense, but the code is well organized and very readable.
yeah, alembic feels especially "small" and obscure compared to the hyper exhaustive nature of SQLA for everything else. felt like a side project at first
Not to mention SQLAlchemy supports the unit of work pattern meaning you can update many objects at once. It tracks and figures out how to apply the updates all in one go. Django supports one object at a time.
With SQLAlchemy it's easy to build mappers to real domain objects that are independent of the database. Most Django people treat the Django models as entities or, worse, do business logic in views etc. It's possible to implement unit of work on top of Django, but that's then another layer you have to maintain yourself (which SQLAlchemy does for you).
But SQLAlchemy is harder. It's better but it's harder. Django is easier to get going with. But it bites you later (unless your app is just CRUD, in which case Django is all you need, well that and a better way to generate HTML).
I class the SQLAlchemy unit of work pattern as one of the harder things: in the cases where Django’s bulk update mechanisms wouldn’t work, it’s extremely easy for someone who isn’t an SQLAlchemy expert to get confused about when changes are committed or to inadvertently leak sessions.
It’s a powerful idea but having helped people with it I’ve mostly felt it reinforce my belief that less magic is usually better from a support perspective.
To each their own, nothing about the first syntax feels miserable to me, my IDE has got me fully supported on it. I don't dislike the SQL Alchemy one though it takes many more lines on my editor (no way I am going to inline all those nested dicts like that).
The problem with Django is not swapping out defaults. The problem is it doesn't like to sit at the edge of an application where it belongs. Django should be equivalent of any other MVC-style framework (like Qt etc), sitting right out in the "interface" layer of your software. But it just doesn't work well out there, mostly due to how tightly coupled it is with its ORM.
Django isn't that, though. That would be something like Flask. Django is batteries-included for one (broad) purpose: you are going to use a relational database to make a CRUD app and we will make that easier for you by standardising a load of stuff. That constraint buys a lot of power.
Nothing is ever just pure CRUD, though. What would you say is the minimum level of business logic where one should consider Django the wrong tool for the job?
One of the problems I find is gradually complexity creep from the business. It starts off as a little clean method here, a signal there etc. Before you know it you've got a domain model tightly coupled to CRUD primitives.
I'd say you should be able to quantify it. "a domain model tightly coupled to CRUD primitives" is not an intrinsic evil. If you were to genuinely save money or reduce risk by, say, moving off a relational database you would just need to pick that point and motivate for a rewrite.
The much higher risk IMO is building a hyper-flexible application from the start knowing what you need today is a CRUD app, just in case in future you need something else. That's how you get shelfware and awkward conversations.
I add one item to my own list: Django admin, being backed by default into the framework is a good thing. Rails has ActiveAdmin but it's a separate gem and it requires more work to integrate. Furthermore, being extra work is something that some customers don't want to pay for. With Django, it's always there.
Django admin is great but it's just CRUD. If you plan to do anything more than CRUD you need to switch off admin at some point. But as a "better than a spreadsheet" database, it's great.
thanks for sharing! The server side story is definitely a consideration why I'm not hyped on Inertia.js for now, this seems to solve it. My current nitpick is my personal preference for Svelte/SvelteKit. I hope you don't mind me taking a look at the repo and try to have Svelte as an option.
I've used rails for years, and have used old versions of django at one company, and used python extensively for non-web purposes.
I think my take is that there's no middle-ground between Rails and some of the newer Java-based frameworks.
Either I'm doing a side project or startup, and I need to go as FAST as possible, type systems and similar be damned, or I'm OK with not going as fast as possible and we're going to go slower but deliver something very solid.
Python/django still had me spending a bunch of time on stuff that rails will either generate, scaffold, or hide from you completely. While still not being nearly as safe or performant as anything in the Java world. Note I'm mostly thinking about more modern frameworks like Javalin, not necessarily Spring's entire ecosystem/way-of-life.
I was not aware of Javeline being used in the same way that RoR/django/Laravel would be used. Javeline provides primitives to build a backend/API layer only no?
Funny you mention templating, its one key thing I'd change about Django, that... and maybe scaffolding, I'd crank it up drastically more.
My ideal enhancement to Django would be something like how Microsoft made Razor into Blazor... A template engine that can run purely on the back-end or purely on the front-end, replacing any need to ever use JavaScript, you stick to your native programming tongue if you will.
I think of Django's templating system as a great tool for a previous era. I'm hopeful that PEP 750 [1] gets accepted and a modern ecosystem of template engines emerges in Python-land. For the moment, I tend to use in-python builders like htpy [2] when I want back-end Python code to generate some HTML.
Didn't know about pep 750, that's really cool that there's a push for native templating. I just hope we see a gradual stepping away of "everything clientside" and the JS framework hell that exists today. I've tried and I've tried but I just can't take javascript seriously. It's so ugly and overbuilt. It should never have been brought to the server, Node was a horrible mistake. In my ideal future, the web returns to servers doing their jobs, and JS being used for minor interactivity features when necessary.
> I just hope we see a gradual stepping away of "everything clientside" and the JS framework hell that exists today.
The nice thing about Blazor is you can either have your templates as WASM, or have them be back-end driven, and Blazor does a bit of the gluing for you so your site updates as things happen and need to be updated, like Phoenix LiveView.
I use htpy and it's great. There are others like htmy[0] too.
The problem with templates in general is you can write malformed HTML in them. The nice thing about htpy et al is you simply can't do that. I feel like what we really want is JSX in Python, where you can write XML-like syntax and it's converted into Python at import time.
PEP 750 started its life in part as a result of learnings from pyxl [0], which used some clever hacks to add a JSX-like syntax to Python.
In the end, my instinct is that t-strings are the better more generic feature to add to the language itself today.
That said, I'd love to see the Python ecosystem get to the point where it's relatively easy to implement transpilers and get new grammars integrated with key tools (colorizers, formatters, linters, type checkers, etc). After that: let a thousand JSX-likes bloom.
Nothing on the python side for templating will ever come close to React or things like that. I built https://www.reactivated.io specifically to let python do what it does best (business logic / backend) and render using React. But all still server side without the downsides of a SPA.
Every developer I know who has adopted Blazor never wants to go back and touch JavaScript. If you do it right, it will sell itself, your market isn't people who use React exclusively, but people using Python and possibly react, but also any other web framework. IMHO the key thing would be a standard similar to WSGI for this system, so it can be implemented and supported by any web framework. ... the more I think about it, the more I am going to have to look at writing a draft PEP...
It sounds like you've already made your choice and it's a good one. Go with Python and make great stuff.
Rails has been around two decades, Ruby three. Both will still be there down the road when you decide to try it out. A lot of what you learn in your Python work will translate in some way to Ruby & Rails.
Majority of learning surface will come from framework and not the language, if you need Python elsewhere just learn that as well, but this shouldn't move framework choice much.
> Majority of learning surface will come from framework and not the language
Once you get past the beginner level in Django, you're going to pick up a ton of Python knowledge (standard dunder methods, MRO, standard lib, data type's im/mutability, package ecosystem, etc.) and muscle memory along the way. Django (for the most part) is just plain old Python data structures, classes, and functions that a decent Django dev will apart, reuse, override, repurpose, and add on to as they do more interesting things. Python is boring (in a good way), however it has a lot of surface area (std lib is massive) and intricacies that a Django dev will pick up along the way to becoming an intermediate/advanced dev. It would take someone coming in fresh to Python quite a while to catch up. Naturally, if the same person knew several languages, the ramp up would be quite a bit quicker.
I want to like ruby lsp but it takes about 8 seconds to get method references in a large monorepo. It’s simply not good enough, and forces anyone looking for a good devex into rubymine
> Ruby seams to only be synonymous with Ruby on Rails.
Seems to be... But it can be used for anything Python is. There's ML libraries, bindings to stuff like Torch, all the math-y stuff like Python, all sorts of stuff. Also it's a great language to just roll your own scripts, programs, etc... Then there's also mruby, which can be embedded like Lua...
If you spend a bunch of time in Ruby (or Python), I don't think you'll have a huge lift switching to the other if you ever want to?
> Rails is still worth using
Yes. Hotwire + Hotwire Native are great tech. The whole suite is integrated in a way that Django isn't ime. I prefer the strong default approach for most things.
One of the biggest things I dislike about Django is its lack of a standard project structure. I haven't used it in years, so things may be different now, but back in the day, even the core team recommended against using the default project layout, which always made me wonder why they generated new apps that way.
Switching between Django projects while doing contract work was always a "what the hell?" experience. Rails' opinionated nature makes it easy to dive into new projects you know virtually nothing about.
Nowadays, I focus exclusively on Elixir/Phoenix apps. Elixir eliminates the OOP requirement (I've never liked OOP because I don't feel it remotely lives up to the hype) while maintaining all the other great things I love about Rails, like consistent project layouts. It also makes writing multi-threaded, distributed apps easy.
This is a bit of a head scratcher for me. I feel Django very much has a way in which projects are supposed to be structured. Maybe you do not like it, but if you ask me where the settings/templates/tests are stored, I could tell you immediately. In a bigger app, where you might want to break things apart, you have options, but it always struck me as you would maintain the existing structure (maybe debate a views/ with multiple modules in there vs views_x.py, views_y.py in the app root)
Unless, you are more angling at the project vs app distinction? Which does seem a bit of cruft. I only ever create a “core” app and put everything in there. Avoids any potential headache.
My only really basis of comparison would be Flask, which has basically zero standard. You can organize your app however you want. Given the barebones nature and need for third party dependencies, no two Flask apps will look alike.
> I only ever create a “core” app and put everything in there. Avoids any potential headache.
I agree with this, but the Django tutorial would lead someone to believe that you need a bunch of apps. So I've seen newbies create way too many apps without understanding why they've done it.
I agree with you. I've wrote very big web applications in Rails, Django, and Java/Spring.
I understand the argument for things being "explicit" in Python, but then I just prefer Java if I'm going to be very verbose about what I want (I'm only talking about backend APIs here). It's just my opinion that whether explicit is good or not depends on the level of abstraction we're interested in, and I don't believe that explicit is always good. (I like the concept of meta-algorithms, for example)
But if there's a one-person project that needs to be scaled quickly, I prefer Rails. (The article mentions how Django makes model fields explicit in the models file, but doesn't talk about schema.rb in Rails which doesn't require you to view each migration to know how the database looks.)
Yes, big projects in any language can get messy, but that's a software engineering problem, not a framework problem.
I recently wrote a FastAPI project that was db-driven, with all the necessary test cases, etc. The amount of lines it took to express the controller, the schemas and models separately, the dependencies for auth and stuff, and especially elaborate test cases was pretty substantial. Yeah, the code was all explicit, but it was not enjoyable.
Unfortunately for Rubyists (myself included) those are huge benefits though nowadays. It's much easier to find Python developers.
Having an out-of-the-box admin interface means business people can operationalize and workaround short comings of the software today, not tomorrow. I think functional admin interfaces can often be the difference between a successful company and one which is constantly operating off of spreadsheets in the background and never fully commits to their software.
The absolute worst Django feature is the templating language. It seems to be designed to slow down developers to the like of old time Java web apps, almost mandatory templatetags et all.
The query language is moderately bad, quite verbose (Model.objects every time) for no good reason.
The lack of common project structure means that every project is different.
There is no Capistrano to deploy. I wrote something like that myself and we have been using it for maybe 7 years.
I'm sure I could go on for a while if I keep thinking about it, but you got the gist of it.
On the Rails side, sometimes I'd like to have a talk with some of the previous developers of the Rails app, which hid some important functionality in a before save callback in a different module for no particular reason, but one can be too clever with Python too. However the language (Python) is quite dull, which can be a good or a bad thing. It's very subjective. It's a Ruby gone bad at design time to me.