loading...
Cover image for Add Some Magic to Your Django Website

Add Some Magic to Your Django Website

adamghill profile image Adam Hill Updated on ・5 min read

Django has been, rightly or wrongly, derided in some circles for not keeping up with modern web development. It even came up in some of the comments of the recent Django Developers Survey. Personally, I don't find that judgment completely fair (all of the work done for asynchronous views is a prime example of Django innovating), however, the story of how to integrate Django with a modern frontend framework isn't super clear.

However, I believe that most sites don’t need a complicated frontend framework anyway. Most websites are not single-page applications (SPAs), but developers are incurring the bloat and site performance of a large frontend framework, in addition to creating more work. Following in the footsteps of the Zen of Python's "Simple is better than complex", I prefer to eschew complexity unless it's needed.

Note: when I refer to "frontend frameworks", I am mostly thinking of React, Vue.js, Ember, and Angular. However, I am currently enamored with a few of the newer micro-frameworks (e.g. Alpine, htmx) and feel they present fewer of the issues I describe below.

Dealing with Javascript build tooling, or: all that glitters isn't gold

Have you struggled with gulp, grunt, browserify or webpack in the past? (Pssst, I heard Parcel solves all your problems! Oh no, wait, maybe esbuild will solve everything?) What happens when a new Javascript toolchain is now the "right" way to build your site? I'd rather not spend the time switching to another tool for incremental improvements because the state of the art changed once again. I would rather spend time working on my app then configuring how to build frontend assets.

Do you enjoy starting a Node.js process to watch for Javascript code changes every time you fire up the Django runserver management command? To me, it is just another complication that gets in the way of the developer experience.

Building APIs and GraphQL, or: using a sledgehammer to crack a nut

The best practice to connect a Django app with a frontend framework is to build REST APIs or, more recently GraphQL. Building that API will take time and effort away from improving the core website functionality. Unless you expect to also support mobile applications, there is a lot of work involved to build a robust REST API. While Django REST framework (DRF) is a brilliant library that encourages sane REST practices and reduces how much code is required for trivial implementations, it is still another framework layered on top of Django. Even with trivial implementations, understanding how DRF works can be tricky.

GraphQL solves some of the object mapping and querying peculiarities of REST, but it has some of the same drawbacks as DRF. Creating serializers for every model and understanding the particular terminology is not trivial. Plus, there is the relatively new paradigm of how GraphQL works and the nuances of how it’s implemented.

Additionally, APIs frequently require authentication, authorization, CORs, and other security measures on top of any normal website functionality.

Juggling frontends templates, or: throwing the baby out with the bathwater

To integrate a frontend framework into an existing Django site, you have to jump through some hoops so that Django leaves the Javascript framework du jour alone and doesn’t, for example, interpret Vue's {{ }} as Django template variables. While doable, it is just another thing to handle. The other complication is switching contexts between Django HTML templates and the frontend framework code. The Django HTML template tends to bootstrap the data and then let the frontend framework handle all of the heavy lifting.

The other approach is to skip Django’s HTML templates altogether and use the brand new API you just built. Either way, you are throwing away the Django template language, a robust and extensible way to convert data into HTML. While not as advanced or contained as frontend framework components, Django includes can be used to build reusable UI components across a website.

A full-stack framework for Django, or: thinking outside the box

Every time I start a new Django project, I go through the same mental calculations to decide how to handle the frontend of the site.

  • Which CSS framework to use?
  • How to configure a CSS pre-processor (e.g. SASS, Less, etc)?
  • Use a Javascript framework or just piece together some micro-libraries and vanilla Javascript?
  • Create a REST API? Set up GraphQL?

For some of these questions, I have some third-party applications I copy from project to project that mostly works, but it is complicated.

One thing I love about Python and Django is the "battery-included" approach. I know that Django has curated an integrated, stable, and secure platform to build server-side websites. I don’t want to have to make other decisions just to have a modern website experience — I just want to create -- not wade through a bunch configuration.

I have been jealously watching developers of other server-side frameworks solving the same issues, namely Livewire in Laravel, a PHP web framework, and Liveview in Phoenix, an Elixir web framework. So, like every other unreasonable developer who doesn’t want to switch away from their preferred language, I thought "how hard could it be to build this in Django?!" (Turns out... it's hard!) I ported a small portion of the ideas from Livewire to Django to prototype how it might work over a weekend and django-unicorn was born.

I've had the definite benefit of someone smarter than myself forging ahead of me — being able to look at Livewire’s technical documentation and screencasts have been incredibly helpful to see exactly what pain points Livewire solves. I have also been inspired by major parts of how the Javascript portion of Livewire works.

Currently, django-unicorn is focused on simplicity and enabling 80% of what a modern website requires. There will always be a need for more complicated SPA frameworks, but if all you need is simple website interactions, then django-unicorn can provide that with a minimal of fuss already.

The basic building blocks are already available in version 0.3.0 of django-unicorn, but I'm still smoothing out the rough edges and adding more functionality. Documentation is also a work in process, but I'm slowly been adding to it to make it as useful as possible. I would love to hear feedback about the idea and additional features to improve the Django developer experience for others. The code is licensed as MIT and PRs are greatly appreciated at https://github.com/adamghill/django-unicorn/!

Unicorn photo by Meritt Thomas on Unsplash

Posted on by:

adamghill profile

Adam Hill

@adamghill

Searching for tech enlightenment.

Discussion

pic
Editor guide
 

Great post.

When I was pondering the same thing, I came up with completely different solution: to use FastAPI with Angular.

It seems to me Django was created for completely different web.

Still, I am using Django because it is comfortable.

 

Yep, FastAPI looks awesome. It's hard to give up all of the niceties that Django gives me, though!

 
 

FastAPI with Vue for me 😊

Nice article and Django is great!

 

Hi Adam.

This is a wonderful project, thank you for creating it! I think it can help on my project. It has a sidebar, and I wanted it to have a component that is a progressbar tracking the user's disk usage on the server.

So far I have created the component successfully using django-unicorn and inserted it into the sidebar. It calculates the disk space percentage and resizes the progressbar accordingly.

Forgive my ignorance, but I can't find a way to change the component's properties outside it's class file, or from my own views.py file. Is it possible to do so? My goal is to update the component whenever there's some user action that impacts his disk usage.

Thanks!

 

Hi Ashirvad, wow that's awesome to hear that django-unicorn might be useful for your project. I haven't thought too much about this use case, but it might be doable in the future. When the user does an action would it be via some Javascript? I'm wondering if there was a hook to call from Javascript to update the component if that could work.

When you mention the views.py portion, I'm wondering if the page is going to be re-rendered altogether? In which case, I think the component just needs to get the correct data in real-time via API or database call or whatever.

In any event, if you could create a Github issue at github.com/adamghill/django-unicor..., that would be helpful for me and we can talk about your issue more in-depth.

Thanks!

 

Hi Adam.

I have just created a Github issue.
Thanks!

Ashirvad

Here is the Github issue and my response in case it’s useful for anyone else: github.com/adamghill/django-unicor....

 

Excellent! I am someone who faced the exact same dilemma after learning and trying out Django in a side project. I am now learning Flutter and contemplating of using Flutter(mobile/web)->gRPC/gRPC-web->Go/Python as the stack for my projecs. But, then, I won't probably need python+Django in that case except for the ORM and admin page advantages it provides. As you say Flutter/Angular/React will also be a heavy lift for some simple projects which don't need the advantages of those frameworks. Thanks for this post and the django-unicorn framework. I will try it out sometime.

 

Having tried out Livewire for a project, I don't think I will be using anything else for any of my projects that involve PHP. The developer experience is pretty neat, especially cutting down the javascript fatigue. Great to see something similar in the Django community. +1

 

Hi Adam, I'm the author of django-reactor I love your project. Is super simple and your JavaScript is better than mine, I actually improved some things in reactor based on your project. Thanks!

 

Oh, nice! I really wanted to keep adding PRs to django-reactor, but after seeing Livewire I got the itch to create something very similar without dealing with websockets at all. I do shout out django-reactor on the first page of my documentation, though! :) django-unicorn.com/documentation

 

I will add support for AJAX as a second option if the websocket drops or configurable, in case you don' want websockets at all.

 

This seems really promising, I was going in the same way, removed the API and was going to try Stimulus and turbolinks.
For sure I will try this.

 

I haven't used Stimulus or Turbolinks in a "real" project, but have played around with them a little bit in toy apps. Definitely some nice ideas in both libraries!