loading...
Cover image for How to Escape the Tyranny of Complicated Javascript in 4 Easy Steps

How to Escape the Tyranny of Complicated Javascript in 4 Easy Steps

adamghill profile image Adam Hill ・3 min read

The internet is full of people telling you how to do complicated things, but I'm always more interested in how to simplify web development. django-unicorn is my attempt at reducing the context switches between Python and Javascript and writing unnecessary code just for simple interactivity on a website.

My goal is for you to continue to use Django and all of its wonderful tools to build server-side websites, and then sprinkle a little magic on top to enable interactivity without jumping to a more complicated frontend framework. See Add Some Magic to Your Django Website - DEV for more reasons to use django-unicorn, or go to django-unicorn.com to read the documentation. However, this article will detail, at a high level, how django-unicorn works.

The basic flow of django-unicorn:

  1. A Django template tag includes the component's HTML. It also bootstraps the component's unicorn:models with initial values based on the component class.

  2. Javascript that listens to events on the component and calls a dedicated API endpoint with specific JSON based on the user interactions.

  3. A Django view that parses the JSON. Depending on the JSON, it will perform an action on a newly instantiated component class. The component class then re-renders itself and returns the new HTML.

  4. Javascript then takes the newly re-rendered component and uses morphdom to intelligently "merge" the new HTML from the re-rendered component into the old HTML.

The Bootstrap

The magic all starts with a few Django template tags. The first, {% unicorn_scripts %} loads the required Javascript onto the page. The second, {% unicorn %} is used to include the specified component.

{% load unicorn %}

<!DOCTYPE html>
<html lang="en">

    <body>
        {% csrf_token %}
        {% unicorn_scripts %}

        {% unicorn 'hello-world' %}
    </body>
</html>

With an initial django-unicorn component, the {% unicorn %} template tag is very similar to the regular include template tag. Based on conventions built into django-unicorn, it looks in unicorn\template\ for a HTML template named hello-world.html and in unicorn\components\ for a component module named hello_world.py and a UnicornView class named HelloWorld.

All public properties and methods found in the component class are registered to be used by the HTML template. Properties and their values are exposed as a JSON object along with a Javascript method call to initialize the component's frontend code. A unique component id and a security checksum based on the initial data are also generated.

Javascript initialization

The initialized Javascript then gets all HTML elements with a unicorn: attribute. If the attribute is unicorn:model than an event listener is attached that fires for input or blur events. Otherwise, whatever occurs after unicorn: is used as the event that is listened to. For example, unicorn:click will listen for click events. Based on the event fired, JSON is created to tell the API endpoint to either update a component's property or call a method on the component. Then, the Javascript POSTs the generated JSON to the API endpoint.

Message endpoint

First, the checksum is first inspected to make sure that the data hasn't been tampered with. Along with the CSRF token passed along with the POST, these prevent a malicious user from changing the data the comes from the frontend.

Next, a new component is instantiated and properties are set or methods are called as specified by the JSON. Then, the component is re-rendered with the new context data. Then new HTML, along with some housekeeping data, is sent back in a JSON response.

Javascript DOM magic

The endpoint response's new component HTML gets magically merged into the old component HTML with morphdom. Then, form elements are set based on the component class.

django-unicorn is currently at version 0.5.0 and works pretty well for simple use-cases, but there is still a ton to do to provide a complete framework to reduce complexity and simplify creating a Django website in the future. I would really appreciate any feedback, GitHub issues, or PRs to help add a little bit of magic back into creating a website.

Unicorn photo by Wilmer Martinez on Unsplash

Discussion

pic
Editor guide