DEV Community

Cover image for Add Some Magic to Your Django Website
Adam Hill
Adam Hill

Posted on • Updated on

Add Some Magic to Your Django Website

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

Top comments (15)

Collapse
 
rafeqm profile image
Muhammad Rafiqi

Thank God! Finally there is a Django tool that I can use to cool my head now. You don't how how many round I've been knocked down by React (and friends) and ASGI Django. I almost leave my status as a Django fans like 2 months ago. But now you bring me back to my lovely Django! Thanks man!

Collapse
 
edelvalle profile image
Eddy Ernesto del Valle Pino

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!

Collapse
 
adamghill profile image
Adam Hill

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

Collapse
 
edelvalle profile image
Eddy Ernesto del Valle Pino

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

Collapse
 
sathishweb profile image
Sathish Ramani

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.

Collapse
 
iancleary profile image
Ian Cleary (he/him)

FastAPI with Vue for me 😊

Nice article and Django is great!

Collapse
 
gayanhewa profile image
Gayan Hewa

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

Collapse
 
ashirvadz profile image
Ashirvad Zaiantchick

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!

Collapse
 
adamghill profile image
Adam Hill

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!

Collapse
 
ashirvadz profile image
Ashirvad Zaiantchick

Hi Adam.

I have just created a Github issue.
Thanks!

Ashirvad

Thread Thread
 
adamghill profile image
Adam Hill

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

Collapse
 
adamghill profile image
Adam Hill

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

Collapse
 
haruanm profile image
Haruan Justino

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.

Collapse
 
adamghill profile image
Adam Hill

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!

Collapse
 
alegume profile image
Alexandre Augusto de Abreu

Very nice!!!