DjangoVue : my favorite full-stack for web development

Will Barillon
10 min readFeb 17, 2023

--

When a web app is developped, there are some pillars you cannot change. Beacons that hints you “We’re doing things right”. Using React, Angular or Vue as front-end for the web app is one of those beacons.

Working around with big data, my web app are always made with Django — front and back. I’m dealing with data displayed on a web page, forms to store more data or to retrived more data according to the user’s need.

I am not looking for a fancy front or very complicated feature worthy to be nominated as the site of the day on Awwwards. Yet, to me, that’s what React, Angular or Vue are very good at.

However, there is one specificity that makes everyone in the big data field use those javascript frameworks : reactive HTML components. And it feels excessive to use a whole framework only to achieve such a simple task.

After a few experimentations and adjustments, I’ve finally found an alternative. It doesn’t involve NodeJS, yet it is elegant, simple and sane.

DISCLAIMER : This article is not a step-by-step tutorial. I’ll emphasize only on files that are important for my custom integration of Vue framework within Django framework.

Sounds great ! But what is a reactive HTML component ?

To explain what a reactive HTML component is, I’ll describe how a web site traditionally works. Back before “one page web site” was a thing — I’ll describe them later on.

You’ve probably already read or seen scheme describing how a client (your computer) and a server (“the web app”) are communicating through requests and responses — requests being sent by the client, waiting a response of the server.

But I’ve never really seen a scheme good enough to explain, and make understandable what implies a request sent from a non-reactive HTML component to a server. So here is a shot of mine with a description.

We’re launching the web app

First request — response interaction between a client and a server

At the first opening of a web app, the client send a request to the server. It requests every features available on a given web page (or endpoint). Features can be pictures, texts, forms, canvas, etc…

Once the request is sent (highligted in red), the server starts services to gather what is needed (in blue). In this case, everything since we’re launching the web page for the first time.

To be more concrete, the request asked the server to retrive data for feature 1, 2 and 3. To do so, the server called necessary services — here named api call 1, 2 and 3 to get some data from the database. Some queries are then running to retrive data from the database — it might take a while. Once data are retrived, services might process them (data validation, changing timezone of dates, success or error messages, etc…).

What you need to understand here, is that sending a response needs a “lot” of work done. Since it is the first time we’re launching the web site we can’t help but doing it.

Don’t get me wrong, the “lot” of work isn’t diminishing the performance of the web site. We’re on the milliseconds scale. Yet, there are several api calls, with several queries sent to the database. The fewer the better fare.

Behavior without reactive HTML component

The web site has none reactive HTML component and the user is about to reload the first feature. It is a form that submit data to store on database. Pay attention to the interaction between the front and the back.

Disproportionate response from the backend

From the perspective of the client, only feature 1’s changed. But with non-reactive HTML, the server behaves as if the client requested to load the whole page again — including all its features.

Instead of having 1 api call, 1 DB query and 1 feature reloaded, there are 3 api calls, 3 DB queries and 3 features reloaded. This is “ok”, it worked like this for years. But I hope that you feel something is wrong and there is room for improvement.

Behavior with reactive HTML component

To avoid this behavior, in the case of web application, we can let javascript handle almost exclusively the HTML : it handles the send of the request, the response sent by the server and the display of HTML. If you’ve played a bit with vanilla javascript it is a tedious work.

Adequate response from the backend

That’s why people designed frameworks to organize and improve the maintanibility of code. Which gave birth to reactive components. This is the reason javascript frameworks are so popular to handle frontend on web applications.

Ok, so how to reproduce reactive HTML components without those frameworks ?

Answer : only use the right parts that you need from those frameworks.

Vue is used only to create reactive HTML component, the rest of the infrastructure (router, controller, architecture, backend, templating, etc…) is handled by Django.

To demonstrate my point, I’ll create a very simple logbook application. One user can enter a logbook entry, which will be displayed on the screen with a datetime stamp.

In other word, we’ll have one feature that is expected to work as shown in the latter scheme.

There are key-files for DjangoVue integration : logbook.html, logbook.js, views.py and forms.py.

Set Django parts up first

If you have no idea how to start from scratch, feel free to read my article on that subject.

base.html

For this file, keep in mind you should adjust the scope of your static js files correctly : files needed everywhere should be called from base.html and files needed from content extending base.html should be called from a block.

In this example, {% block js %} will be used by logbook.html to call logbook.js.

utils.js file contains 2 functions that will help building the query with fetch() and send data from front to back in logbook.js.

vue-3.2.47.js contains the whole Vue framework intelligence needed for the task. It doesn’t contain every features from Vue such as router-link, you can truly build component in the “Vue-way” and is limited to the API option. But you can improve the redaction of your javascript code and exploit the Vue templating alongside Django templating in HTML pages.

Here is the link toward the CDN version of Vue 3.2.47.

logbook.html

Although the feature is simple, the html template seems a bit complicated and odd. That’s because Django and Vue are intrincated together to create this reactive HTML component. Let’s decompose a bit.

You can distinguish 2 parts : the part where logbook entries are displayed and the part where entry are inputted in a form.

At first, the Django template handles entries which are already stored in the database. Once the page is loaded, Django handles the display of entries.

For entries added while the user is on the page, they are displayed by Vue. A short words for those not familiar with Vue :

  • v-for is the for-loop syntax
  • @click is the click event listener
  • :key is a way Vue use to bind the value of a html element to a javascript variable — let’s call it like that for now

For both Django and Vue, I added getEntry, a javascript function — or should I say, a method from our logbook Vue app — to get the id of a given entry in order to send this id on the backend-side and do CRUD operations on it.

Then, we have the “DjangoVue” form where :

  • @submit.prevent is used to prevent the default behaviour of the form and replace it with the logbook method submitForm
  • Since cybersecurity is not an option, the sending of data is done with POST method coupled with the django csrk_token tag
  • Finally, form inputs defined in forms.py

forms.py

Nothing very complicated for people having a background with Django — who are supposed to be the main audience of this article. So I’ll just describe this vue HTML attribute v-model.

v-model allows the previously introduced “javascript variable” to track what is written in the input of the form. Without it, our POST request shall be empty. It has to be used in pair with the other HTML attribute :key also introduced above.

logbook.js

As you can see, not much changed from good ol’ vanilla javascript. I only respected option API syntax of Vue framework.

Keep in mind that logbook is an object. With methods, attributes and reference to itself (or should I say itthis . . . sorry). But you can also declare and use javascript variables such as csrftoken on line 10 or query on line 18 in the illustration above.

First thing to notice is that Django and Vue have by default the same delimiter for templating : {% %}. As you can expected, a conflict arise if you don’t distinguish them. Fortutately, Vue propose a way to resolve the conflict in a simple way with the delimiters field — I don’t name it property because Vue objects have properties too at that level.

  • data is the main place where the interactive variables are. They act as attributes of logbook object and can be manipulated through methods, properties, computes, etc…
  • mounted() is one of the Vue lifecycle hooks. For this project, I’ve used mounted() as a scope where I declare my variables once the HTML element is loaded
  • methods is the place where I set my functions
  • mount() take as parameter a css selector to determine the scope of the Vue object within HTML

Why use fetch() when every tutorial dealing with the same subject is using axios ?

As you can notice, I didn’t use axios to send my POST request to the server. fetch() is well-suited for the job and already integrated in ECMAscript. Furthermore, I don’t think there isn’t a specific reason to chose axios over fetch for most of web application.

Here is a lecture I found instructive about axios and fetch differences.

views.py

On this part, I want to describe what get_latest_entry from fetch() do.

It might seems odd to retrive the last logbook entry written by the user from the database, when it is already on client-side. But I have a very good reason.

My logbook application doesn’t only display the entry, but also the datetime stamp. And I have to work around 2 constraints :

  • date and datetime field are stored at UTC timezone in database. It is a good practice because it allows the web application to reach international scale without having to deal with different timezones stored in database.
  • date format has to be like so : day/month/year, hours:minutes:seconds — yes, the comma is part of the date format.

To work around those constraints, there are 2 options :

  • client-side with javascript by creating an object with the entry and the datetime stamp, on the right format, then push it in the template among the others logbook entries. Of course, before doing all that, we need to make sure the entry is stored on the server
  • server-side with python by retrieving the entry from database, adjust the timezone and send the entry in the fetch response

Are we seriously considering the second option ?

Knowing the reputation of javascript to be a nightmare at handling datetime and formatting them, yeah.

I did a minimal benchmark about those options and… the result will surprise you — I hope to the extent it surprises me as well !

First option, mean = 96 ms
Second option, mean = 90,4 ms

Not only the second option stands at the same range than the first option, it also is slightly faster !

But my way of formatting date might be the cause of this poor performance.

Conclusion

I’m really excited to use this new DjangoVue way of doing things with my next project. I’m completely independant from javascript dependencies, which are very popular on the web community — and in hacking community. I’m virtually saving my applications from worrying about vulnerabilities issues regarding node packages or other javascript dependencies.

Furthermore, as I’m not handling node_module either, my web application are lighter. Which facilitates their deployment and availability.

I’m really curious to see the exact same logbook entries web application developped with React or Angular. It would be an opportunity to see the differences regarding architecture, size and performance.

If you want me to release the logbook web application on a public repo, feel free to avise me with a comment.

--

--

Will Barillon

A python developer / data scientist that wants to provide useful informations to everyone.