Django made me fall in love with programming 13 years ago, and since then it has always had a special place in my heart.
I’m revisiting a business idea I was working on for a couple years, before I sought and found employment in the industry (where I used Java for a couple years, then Elixir for a couple more). My project was built with Django and Django REST Framework, and Ember on the client-side. 6 years later, the Django side needed minimal changes and is up and running (I jumped all the way from 1.11 to 5.0 beta).
Meanwhile, the Ember part is “lost in time… like tears in rain”. I tried everything, downloading older versions of Node and even the now-deprecated Bower. I don’t fault Ember (which is actually the most stable of the major JS client frameworks). But the JS (especially Node) ecosystem is beyond redemption in my eyes.
For my rewrite of the client, I’m going to skip the drama and just use htmx. Render Django templates server-side, include a single JS script, thrown in some HTML attributes, distinguish between full page requests vs. requests for a partial with updated data, and call it a day. No TypeScript, no Webpack, none of that nonsense. If I need special interactivity I can throw in some hyperscript.
At work I’ve used Elixir/Phoenix/LiveView and it’s revolutionary, truly awesome tech. But to get to market I would rather not have to customize an auth system and build a decent admin interface myself (I tried Ash; its auth and admin are not mature enough to be compared to what “just works” with Django). Yeah, it won’t be as scalable as a Phoenix app, but to me, Django seems like the most clean and rapid way to get to a point where you’ll actually need scalability.
> 6 years later, the Django side needed minimal changes and is up and running (I jumped all the way from 1.11 to 5.0 beta).
I've been using Django since before 1.0, and the upgrade story has been nothing short of fantastic for something that's been around this long. But still, YMMV!
Depending on how ancient a project you run into, it definitely can be a major pain, even with the original authors' best intentions. For example, Django didn't have its own DB migration system until 1.7 (relying on third party solutions); this means you also have to adjust the deployment procedure, which means recreating an ancient setup (ideally in an easily repeatable fashion, because you're going to be trying that migration at least a dozen times).
The builtin admin system is also a pretty decent CMS on its own, but falls short as you run into slightly more complex use cases (such as basically anything that requires even a single line of JS). The docs will encourage you to copy and override the builtin templates; this often becomes a pain point during upgrades. It's wise to get off the builtin admin system as your project grows.
FWIW I've also had the same experience; the last version of Django where upgrading took a non-trivial amount of time was 1.8, because it changed how isolation is enforced within test cases. Since then it's rarely taken more than an hour or two, regardless of how big the codebase is.
Wagtail is absolutely fantastic for content-heavy websites, like blogs, journals, catalogues, archives, venues (event schedules), also everything that deals with loosely-structured data. It's much less useful as a general purpose CRUD framework - it's too focused on "content", it wouldn't spark joy.
Also it's been a few years since I've last used it, but the overwhelming dominance of deeply nested JSON fields makes ordinary DB migrations unnecessarily interesting.
Maybe I'll expand a little bit on the context... Both "CMS" and "CRUD framework" were unfortunate choices of words, and don't quite represent the actual problem.
The Django Admin implements the MVVM pattern; you declare a "ModelAdmin" (aka a ViewModel) subclass, where you can say things like "display the fields in this order" or "run this function to validate that field", and never ever touch any SQL, ORM, HTML, etc until necessary. It is extremely powerful: every line of declarative code saves you hundreds of lines of writing the lower layers; every line you can't write declaratively, can be instead expressed by a mere dozen, using the built-in escape hatches. This pattern of getting "just one layer below" can continue for quite a while, until you suddenly run into an unexpected hard wall.
For example, there is no way to mix the ordering of "fieldsets" and "inlines" (the latter being the only meaningful way to support M:N relations). The community has gathered a couple hacky workarounds (like post-processing the generated template to re-order the sections), but to address the root of the issue would be to merge "fieldsets" and "inlines" into a single property that controls both. So I've embarked on that task, and started hacking on the admin, only to find some of the most gruesome spaghetti entangling the path - I suspect big chunks of that code were hastily thrown together in mid-late 2000s, and barely touched since.
This is a recurring problem - almost every single customer I've talked to is about 95% happy with using the Django admin, but these tiny things that require disproportionate effort keep ruining our day.
Wagtail is not a general solution to this problem; it solves some of the larger pain points (for example, by liberally using JSONFields, which as I've mentioned come with problems of their own), but actually makes editing larger amounts of more structured data a bit more awkward, since it doesn't even come with all of Django admin's (limited) flexibility, and mixing the two in a single project results in an unmitigated UX disaster.
I think I have a pretty good idea of what I'd like to replace Django admin with, unfortunately I've done extensive research and none of the existing alternatives are quite it - you always have to give something up, because the tool is too specialized, makes too many assumptions about your use case. However I think the core principles of Django admin hold very strongly; it's just that the implementation is lacking, and probably will never be addressed, as ease of upgrading will always continue to win (and kudos to Django for that - again, I've been through quite a few legacy projects).
I think there is space for a third-party admin replacement that adheres to this spirit, but breaks all backwards compatibility to clean up the architecture. It would require careful and conservative tech stack choices; I'd like it to survive the next 20 years and allow projects built today to enjoy the same easy path forward. I'd be more than happy to work on that, unfortunately I'm a little preoccupied bending the existing code to my will ;)
I'm with you on this, Django + HTMX + Vanilla JS (where needed) just works which is a beautiful thing.
Is building out the UI clunkier with Django templates than with JSX? Absolutely.
But not having to worry about both server and client side state is such a time saver and you know it is going to continue to work.
For the past few years I've been using Go (using Gin) in place of Django, and it works nicely and is quite a bit faster. However, recently I've been toying around with Django again, thinking about making it my default for new projects because it really does take care of so much that you'd otherwise have to deal with yourself.
An approach I've done in the past for projects that are publicly API-based:
Django handles the database migrations and user accounts/models/etc - and you get the useful admin to boot, which is just incredible if you ever need to open up the data layer to someone else.
Then just write the API interface in Go/Rust/your language of choice. It decouples the DB modeling from the API layer, but in practice... I've just not run into significant issues with it. I'm sure it could be an issue though, so YMMV.
It's not a bad idea, but the tradeoff is usually you'll have to define your models twice. For whatever reason, that tends to happen anyway, so not that big a drawback in practice.
Eh, in my case I prefer writing raw SQL for the API side of things - it's more apparent what's going on in code that I actually tend to wind up debugging down the road. As a result I don't really feel like I'm writing models twice - I model then code, then just read it directly, if that makes sense.
You are ultimately still right, I think - just a personal nuance I guess.
As a full-time Node.js dev, I agree with your decision! Too much time is wasted on compatibility problems. I'd almost say it was easier when we just had browsers to deal with. At least you could just drop in jQuery and call it a day.
Yes, jQuery is often derided as outdated, but it worked quite well for a very long time, with minimal hassle for developers. In fact, I was working full-time on static Elixir/Phoenix pages with jQuery sprinkled on top as late as 2022… it felt a bit clunky but it worked as advertised and wasn’t frustrating in any significant way.
I absolutely agree. Recently I had to work on a complex client app, and I could simply not believe the amount of trouble you have to go through when you want to increment the version number of things like React, MUI, webpack, TS by.. one!
Breaking changes can vary between 'these one or two things out of thousands must be changed' and 'yeah we did a rewrite and its a new library but we kept the name as its pretty well known'.
> I’m going to skip the drama and just use htmx for the client-side. Render Django templates server-side, include a single JS script, thrown in some HTML attributes, distinguish between full page requests vs. requests for a partial with updated data, and call it a day.
More of a side comment, but I'm skeptical of the way HTMX encourages partial renders like this. It feels like a premature optimization that adds more complexity on the back end. `hx-select` takes care of it, but to me it feels like it should be the default (it's what Unpoly does).
There is a package, https://github.com/carltongibson/django-template-partials, that is basically like server-side hx-select, when there is some performance concern. Overall, I agree with you though, hx-select is going to be fine most the time.
Thanks for sharing that! I also just finished watching Carlton’s talk from DjangoCon EU (linked in the repo) and it is gold: https://youtu.be/_3oGI4RC52s
There is a header that htmx injects to indicate you want a partial render, and it’s really not that hard to add an if on the server-side to check for it. A larger codebase would probably break templates up anyway for maintainability, so it’s just a tiny amount of extra work if you want to reduce the amount of HTML being sent over the wire and swapped in.
Django and django-unicorn is really nice. It feels like meteorjs but for Django, extremely productive. I've been working with the creator closely and he's awesome.
I haven't used Elixir yet and mostly using flask in Python for work but I started with Django (and still think it's better than flask for most apps). If stuff like https://github.com/aesmail/kaffy (first thing I've found on google, never heard of it before) is on par with the Django admin, would you still use Django or Elixir and never look back?
I don’t know if I would “never look back” to Django (I’m a sentimental person). But admin is one aspect, the other big one is auth. I also like DTL better than EEx/HEEx. And all the pieces of Django just fit together really nicely; where Ecto happens to be the preferred way to interact with a database from Elixir, and Phoenix happens to be the preferred way to build Web apps using Elixir, (maybe with Ash layered on top), they weren’t designed by the same people, so you have packages like ecto_phoenix, ash_phoenix, etc. to make them all play together in an elegant way.
I will admit, Elixir and Phoenix have better real-time and scalability stories.
If I had a choice I would probably prefer Elixir/Phoenix/LiveView when joining an org to work on an established codebase that may have actual scalability needs and concerns. But I would probably prefer Django when starting from scratch.
If you want a heavyweight JS framework, Ember is the most stable and best supported. I enjoyed Ember when I used it in the 2015-2017 time frame.
But I’m abandoning the heavy JS paradigm in favor of htmx. Aside from the fact that I don’t want to duplicate routing and data validation across client and server, htmx is intentionally a single JS file with no build step, so in theory it should run fine as long as browsers maintain backward compatibility.
Fwiw trying to get an old ember app running was an absolute nightmare. On top of that it is way too heavy for my liking. Pretty much polar opposite of jquery.
i've been using django + htmx and vanilla js where needed. it's great!
my biggest beef with it is code organization, which will only get better with more experience. and it's a side project so it doesn't matter. i do worry about using it on a team because i could this stack getting messy if not done the right way.
I’m revisiting a business idea I was working on for a couple years, before I sought and found employment in the industry (where I used Java for a couple years, then Elixir for a couple more). My project was built with Django and Django REST Framework, and Ember on the client-side. 6 years later, the Django side needed minimal changes and is up and running (I jumped all the way from 1.11 to 5.0 beta).
Meanwhile, the Ember part is “lost in time… like tears in rain”. I tried everything, downloading older versions of Node and even the now-deprecated Bower. I don’t fault Ember (which is actually the most stable of the major JS client frameworks). But the JS (especially Node) ecosystem is beyond redemption in my eyes.
For my rewrite of the client, I’m going to skip the drama and just use htmx. Render Django templates server-side, include a single JS script, thrown in some HTML attributes, distinguish between full page requests vs. requests for a partial with updated data, and call it a day. No TypeScript, no Webpack, none of that nonsense. If I need special interactivity I can throw in some hyperscript.
At work I’ve used Elixir/Phoenix/LiveView and it’s revolutionary, truly awesome tech. But to get to market I would rather not have to customize an auth system and build a decent admin interface myself (I tried Ash; its auth and admin are not mature enough to be compared to what “just works” with Django). Yeah, it won’t be as scalable as a Phoenix app, but to me, Django seems like the most clean and rapid way to get to a point where you’ll actually need scalability.