Exploring Frontend Options for Django Applications
Going beyond React + DRF. But maybe not surpassing it.
Django is now 20 years old. And Django’s frontend development philosophy is also 20 years old.
Server-side rendering (SSR) with HTML templates worked great in 2003. But the requirements of modern web applications are increasingly difficult to achieve using Django’s default frontend templating engine.
Today, many (if not most) large-scale Django applications do away with using Django templates altogether. It’s much more common to see organizations build out decoupled React Single Page Applications (SPAs) and then connect them to Django backends which are solely responsible for serving data.
In the minds of some developers, this is overkill. And so a third philosophy has come into play, which attempts to marry the simplicity and rapid development of Django’s SSR with the dynamicism of modern JavaScript frameworks. This involves the use of lightweight frameworks like htmx and alpine.js to enhance the functionality of Django templates.
But even htmx can’t compete with the feature-completeness, community, and 3rd-party package support of a full SPA framework. With that in mind, I set out to explore a different hybrid approach, using Vue.js within Django templates. My theory was that this would truly be the best of both worlds: the ability to scale up beyond the feature boundaries of plain Django templates/htmx/alpine, while also reaping all the benefits that come from using the Django templating engine.
But before I do that deep dive into Vue + Django, I’d like to use this article to do an overview of these 4 competing philosophies. This should shed some light onto why people would choose one approach over another, and why I felt the need to explore a new option.
Table of Contents:
- Comparison Chart
- 1. Django Template Server-Side Rendering (SSR)
- 2. Decoupled React SPA
- 3. htmx with Django SSR
- 4. Vue with Django SSR
- Conclusion
- Further Reading
Comparison Chart
I’ve narrowed down the main differences between our 4 approaches to these 6 features. They’re listed in their rough order of importance to me. In the two areas where both htmx and vue both have yellow rankings, htmx edges out as the winner.
Legend:
Feature \ Approach | Django SSR | React SPA | htmx + SSR | Vue + SSR |
---|---|---|---|---|
Development Speed | Best | Worst | Somewhere in the middle | Somewhere in the middle |
Feature Completeness (Can it build moderately complex UIs?) | Worst | Best | Somewhere in the middle | Best |
Learning Curve for a Backend Python Developer | Best | Worst | Somewhere in the middle | Somewhere in the middle |
Integration with 3rd Party JavaScript Libraries | Worst | Best | Worst | Best |
Community Support | Best | Best | Somewhere in the middle | Worst |
Support for Django Template tags | Best | Worst | Best | Best |
Primarily, I want a frontend that can be developed quickly. But I also want a frontend that isn’t restricted in what features it can implement.
But there are other factors to consider. If I hand off the project to a mostly Django backend team, will they be able to easily maintain it? Can we plug in helpful 3rd Party JavaScript libraries easily? Is there a larger community out there that has solved some of the low hanging fruit issues that I’ll run into? And can I utilize the good parts of Django templates if I need to?
If you look at the zig-zagging greens and reds between Django SSR and React SPA, you’ll understand why people are motivated to explore new approaches. The strongest points of Django SSR frontends are the weakest points of React SPA frontends. And vis versa. You can’t get the benefit of one without a big tradeoff in another area.
htmx + Django SSR has more feature completeness than vanilla Django templates, but still won’t compare to the functionality of a full JavaScript SPA. I’ve found that using Vue + Django SSR can bridge that feature gap, but at the cost of other quality-of-life factors.
Let’s explore how each of these approaches work in practice.
1. Django Template Server-Side Rendering (SSR)
If you follow Django’s official tutorial, this is still how they’ll tell you to develop your frontend views. Render your template on the Django server and send it to the client. If your users have any changes to apply, they send an HTTP request back to the Django server, and Django serves back a new rendered template.
The flow looks like this:
And if you do want to include any interactive elements, you’re free to load any JavaScript static assets that you want:
With this approach, you can add JavaScript/jQuery incrementally. But the majority of the rendering is going to be done with static Django HTML templates.
This means that by default, nothing is dynamic. If, for example, you submit a form request, the response that gets returned will have to reload an entirely separate Django template. This is where the 20-year-old frontend development philosophy starts to show its age.
Pros:
- Rapid Development: Django SSR can quickly scaffold a basic web application. This works great for very simple CRUD applications.
- Django Templates have their place: There are some ways that Django templates are actually really good! Limited though they may be, creating automated ModelForms out of Models is a blessing.
- Ease of Use: Requires minimal (if any) JavaScript. This is great for backend developers who know Python and HTML, but not necessarily React/Vue/Angular.
Cons:
- Limited Interactivity: Dynamic content requires additional JavaScript or AJAX, potentially leading to complex and unmanageable code. There comes a point where it would have been simpler to just write everything in React.
- Static UX: Every user interaction typically results in a full page reload, contrasting sharply with the fluid experience offered by modern web apps.
Notable Open Source Examples:
- consumerfinance.gov — Look at this! Good government software!
- Django Polls Tutorial — Thanks to Digital Ocean for building the tutorial app for us.
- django-extensions — A popular Django utility library, their repo has some good sample apps.
So then the question is, how complex does my application need to be before I need to make the switch to a React SPA? Like, I’m not trying to build an airBnB or Google Docs or whatever. What if I’m just building a totally basic, totally utilitarian, business CRUD application?
In my experience, the answer is that you’ll hit that limit faster than you’d think. Even business users expect a level of interactivity that Django templates weren’t designed to handle. Do you want autocomplete in your form fields? Conditional form fields? Instantaneous filtering? Updating a single row of data without triggering an entire page reload? These are basic CRUD features that in 2024 every business user takes for granted. But to implement them in Django templates you’ll have to either build them out from scratch or use a patchwork of spuriously-maintained 3rd party packages designed to work around Django SSR’s limitations.
It’s no wonder why so many teams opt to just use React instead.
2. Decoupled React SPA
“React” is used as a stand-in for any JavaScript SPA framework (Vue, Angular, etc.). The developer experience and pros/cons are fundamentally going to be the same.
With a decoupled React SPA approach, we take the “View” responsibilities away from Django and delegate them a separate React application with its own build, deployment, and development process. Django is responsible only for serving the data to populate that React application, probably using a package like django-rest-framework (DRF) or graphene-django.
It requires a bit more upfront effort to get running — developers now need to maintain a React application and all of its associated friends (Webpack, Babel, TypeScript, npm, etc.).
Which is fine! It’s not as bad as the memes make it out to be. I wouldn’t discourage anyone from learning React development. But the point is, you’ve now got to add a capacity to your team well beyond the bounds of Django development.
But once you’ve gone through the trouble of building out your React application, a lot of nice UX features are made a lot easier. Such as updating pages without requiring reloads:
Pros:
- Dynamic UX: Your application can be fully interactive with no page reloads required. You may not get the benefits of Django’s own intergration with its templates (like ModelForms) but you won’t be hindered by their limitations either. Pretty much any requirement that a modern web application could require can be handled by your SPA.
- Modern JavaScript Ecosystem: Tap into the full React ecosystem of UI frameworks and libraries: no need to ever reinvent the
datepickerwheel.
Cons:
- Complexity: Requires proficiency in React and JavaScript tooling, increasing the learning curve for developers.
- Longer Development Time: Managing two separate codebases can complicate the development and deployment process.
Notable Open Source Examples:
- Wagtail — A robust open-source CMS platform, and a leader in the open-source Django community.
- Sentry — One of the most popular application monitoring tools happens to be built in Django.
- Posthog — This is a great example of using DRF (with typing!)
Now let’s explore some experimental options that are attempting to get the best of both worlds.
3. htmx with Django SSR
Full disclosure: I haven’t tried this stack yet. I’m still wary. If the theory holds, and it can address all of my business CRUD application feature requirements without needing additional JavaScript, then I’d be happy to adopt it. But right now, I’m concerned that it’ll just push the feature-completeness boundary slightly farther than Django SSR templates, but I’ll still end up hitting a dead end. If you have some notable examples of feature-complex htmx apps, please send them my way!
The Django + htmx stack is a emerging trend that’s designed to get the Dynamic UX benefits of a React SPA, without the Complexity downsides that comes with it.
htmx is a lightweight web framework designed for making dynamic things easy to do without writing your own JavaScript. No build process required!
How this works is you inject an htmx script into your Django templates, which now enable you to use special htmx attributes like hx-post
. You’ll have to make receivers on the Django server to handle any update actions, but you can do that without necessarily decoupling all data operations from your Django Template View.
Now, instead of returning raw data from your Django server, htmx returns HTML partials that update your template.
Pros:
- A Simpler way to get Dynamic UX: Easy to integrate with existing Django templates. Static content stays static, dynamic content gets to be dynamic.
- No Heavy Frameworks: You get that interactivity without requiring React or any complex JavaScript build tools.
Cons:
- Scalability: I’m still not sure what the limit is for htmx. Can it handle all of the moderately complex user interactions that are required for modern web applications? Where’s the cutoff point where React becomes required?
- Limited Ecosystem: You don’t get access to the excellent community packages offered by the modern React / JavaScript ecosystem. I mean, there’s nothing stopping you from using them. But they’ll integrate with your forms + apps as well as they would in vanilla Django templates (i.e. not terribly well).
Notable Open Source Examples:
- realworld — realworld is a project that every web developer should know about. It’s the same demo app, but reimplemented in just about every combination of frontend and backend that you can think of. This particular implementation uses Django + htmx + alpine.js. A great resource for anyone looking to learn this stack.
By all accounts, the early adopters of htmx love it. But I still have my reservations about going completely without JavaScript.
Which leads us to my foolish attempt to truly get the best of all worlds.
4. Vue with Django SSR
My thinking was, if people are injecting htmx into Django templates, why not just inject Vue instead?
The setup uses the same conceit as htmx. Add a vue script to your Django template, and now your components are as interactive as you need them to be.
If needed, your application features can scale up to the level of complexity offered by a full React and/or Vue SPA. And you get to use any JavaScript library you want, including the world’s greatest datepicker.
Pros:
- Island Architecture: You can inject dynamic components anywhere without commiting to writing your whole Frontend application in React/Vue.
- Access to the modern JavaScript ecosystem: You have the ability to use all modern JavaScript UI frameworks and packages as you see fit, just as you would with a decoupled SPA.
- No limits to functionality: Scale up to the full functionality of an SPA, all within a Django Template.
Cons:
- Still requires knowledge of JavaScript development: You’ll have to learn Vue. And you’ll have to learn a JavaScript build tool like vite. Fortunately, there’s this supergood site that can help you.
- Trapped between two worlds: It gets complicated moving from vue-controlled elements to Django template-controlled elements. During my work-in-progress exploration, there were many times when it felt like it would’ve been easier to either fully commit to an SPA or fully commit to Django templates.
- It’s the Wild West: There are no established open-source best practices for handling all the edge cases you’d need to support a production application. There are a handful of trailblazers that we’ll shout out in further reading, but there is not really community support to speak of.
Notable Open Source Examples:
- Canopy LLC’s hybrid-form-example: One approach to using Vue to support Django forms.
- cookiecutter-vue-django: A cookiecutter and example app that offers some helpful patterns.
- supergood-reads: My own attempt to inject Vue into Django templates. Proceed with caution.
Conclusion
Despite all the work I’ve put into trying to get Vue to interoperate with Django templates, if I had to build a production Django application today, I’d just go with React + DRF. It’s slower, but I know it’ll work, and I know I’ll never hit a wall with what features I can deliver.
I’m keeping an eye on htmx. It would be great to be able to speed up my development time and use more of Django’s built-in template utilities in my frontends.
And I haven’t given up on using Vue with Django templates. It may not have been the silver bullet I had hoped, but I think there may be a place for it. Stay tuned for a deeper dive into my explorations with Vue and Django templates!
🔆
Further Reading
On Vue + Django:
- Mike Hoolehan, Vue + Django: Combining Django Templates and Vue Single File Components without compromise (DjangoCon US 2023)
- Canopy LLC, The Best of Both Worlds: Using Vue and Django Together in a Hybrid Approach (DjangoCon US 2022): This is the only production example of using Vue in Django templates that I’ve found.
- Cory Zue, Modern JavaScript for Django Developers (DjangoCon US 2021): A DjangoCon talk that gives a good breakdown of the tradeoffs between vanilla Django SSR frontends vs React SPAs.
On the SPA + DRF approach:
- HackSoftware’s Django Styleguide: A good set of DRF best practices.
On the htmx approach:
- Anatomy of a Django/HTMX Project: A write-up by the author of the Django + htmx realworld implementation.