How to build an App with Django, Turbolinks and Stimulus
TL;DR
So you want to have a little starter? Great because I built one for me here with this tutorial :)
A real-world problem
I started to work on my Bachelor Thesis a couple of weeks ago. I'm building a Recommender System for a B2B-Application and needed a dashboard to show some stats and information. In the last one and a half years I mainly worked on React-Applications, lately some Next.Js. But I didn't want to blow my whole Django application with an additional react application, because that meant I needed to implement a fully-featured rest-API for every information stored in the database. But what I wanted to have is the feeling of a single page application. I knew, that the good guys at basecamp built something like that. And that thing was a combination of turbolinks and stimulus. I always wanted to try this different approach to building modern web applications. But I never had a real "opportunity" for this. So now was the time.
Techstack
Another part of my seeking of knowledge was the implementation of webpack in a Django app. I never used it before in Django applications, because I only used Django to create rest API's for my machine learning projects. And they had a standalone react-frontend built with create-react-app (terrible, I know).
So here are the parts we will have in our Application:
- Webpack
- Turbolinks
- Stimulus
- Django (managed with pipenv)
Starting the environment and installing the python dependencies
Start by creating a folder. You can call it how you want it, but i will use the name django-stimulus-turbolinks-starter.
All my non-jupyter python projects start with the simple usage of:
pipenv install --python=3.7
So now we have our basic python environment. Who does not know pipenv, you could describe it like the npm of the python world. Check it out here
After the successful creation of our environment, we want to start the shell so we do not need to specify the python version we're using:
pipenv shell
At this point we start to work in our virtual environment. The perfect moment for the installation of Django.
pipenv install django
When the installation is finished, we want to start a new django project:
django-admin startproject dsts .
The dot at the end means that we want to start the app in the current directory. The "dsts" just is short for "django stimulus turbolinks starter".
I almost always add the first application after this point:
django-admin startapp dashboard
I called it dashboard because that was the name of the first app i used in the code of my thesis.
So far, so good! We set up a basic little django application. At this point we will leave the python world to start implementing the javascript side of this project.
Initializing and setting up the npm-project
So npm. My first love of package managers. And honestly it's still the best I know. No doubt. So here we start with the well-known command:
npm init -y
To speed things up, I added the -y Flag. In case you don't know what the y-flag is doing, read it up here.
As the next step we need to install our dependencies. I added some more than only the packages we really need. So we have some additional file loading, babel, and so on. But first to the most important part:
npm install webpack webpack-cli stimulus turbolinks css-loader file-loader --save
But we need some additional packages for our dev-dependecies:
npm install --save-dev mini-css-extract-plugin nodemon @babel/core @babel/plugin-proposal-class-properties @babel/preset-env babel-loader webpack-dev-server
And that's it! We have the most important parts of our application ready to use.
Creating and changing the config files
To use webpack correctly in the application we need to create a config file. In this config file we can implement all our wishes for the bundling. I found this tutorial about webpack pretty useful. In the chapter above we added MiniCssExtract as a dependency. We did this, to get an additional CSS file through webpack, so not every style will be added into the header of our site. Additionally to the webpack config file we need to make some changes to the package.json and the settings.py of our django app. But let us start with the webpack config.
The Webpack Config file
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: 'development',
entry: './static/js/index.js',
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
'@babel/plugin-proposal-class-properties'
]
}
}
}
]
}
}
As you can see we currently just have rules for CSS and javascript. To get more information I recommend watching the tutorial I linked above.
package.json
In this file we will only add two lines of code to the script section. We will add a build and start command.
"scripts": {
"start": "nodemon -w webpack.config.js -x webpack-dev-server",
"build": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
To be sure we will use the npm run build-command right away, to create the dist folder.
settings.py
At the beginning of this article we created the first application, so I will use this moment to add it to our installed apps section in the settings.py. If you want to learn more about django I recommend the tutorials of Corey Schafer. He is, in my opinion, the best python teacher out there. His content is free I and always found an answer to a question I had.
INSTALLED_APPS = [
// just add it at the end of this list
'dashboard'
]
// at the bottom of the file
STATIC_URL = 'http://127.0.0.1:8080/' # for webpack dev
STATICFILES_DIRS = ['dist'] # for the generated dist folder
And that's our tech stack!
The index.js, index.css and the first stimulus controller
To get the app fully working together we need to add some additional folders. At the static-side of things we need to create a static folder in the root directory. We already have seen where it will go, in the webpack.config.js And in our app dashboard we'll create a folder called "templates".
So this will look something like this:
django-stimulus-turbolinks-starter
| dashboard
| | templates
| static
| | css
| | | index.css
| | js
| | | controllers
| | | | hello_controller.js
| | | index.js
index.js
import { Application } from 'stimulus';
import { definitionsFromContext } from 'stimulus/webpack-helpers';
import Turbolinks from 'turbolinks';
// import css
import './../css/index.css'
const application = Application.start();
const context = require.context('./controllers', true, /\.js$/);
application.load(definitionsFromContext(context));
Turbolinks.start();
index.css
.content {
max-width: 300px;
margin: auto;
}
p {
font-size: 32px;
}
Here we create our Stimulus and Turbolinks Application and added some super basic styling. I hope that this code is self-explanatory.
static/controllers/home_controller.js
import { Controller } from "stimulus"
export default class extends Controller {
static targets = [ "name", "output" ]
greet() {
this.outputTarget.textContent =
`Hello, ${this.nameTarget.value}!`
}
}
This is the same controller you can see at the Stimulus homepage. I won't go deeper into stimulus in this tutorial. If you want to learn more, I recommend reading the documentation.
templates/home.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="{% static 'main.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static 'main.css' %}">
<title>Django Stimulus Turbolinks Starter</title>
</head>
<body>
<div data-controller="hello" class="content">
<p>
Hello Stimulus!
</p>
<input data-target="hello.name" type="text">
<button data-action="click->hello#greet">
Greet
</button>
</br>
<span data-target="hello.output">
</span>
</div>
</body>
</html>
This is the first moment we see a django template together with a stimulus controller. And surprise surprise, doesn't look unfamiliar, right? That's because we don't need to add any javascript at this place. Pretty neat!
Serving the template and starting the application
Congratulations! This is the last step of this tutorial :)
As the last step we need some additional lines of code in our django code to fully serve our django-stimulus-turbolinks application.
dashboard/views
from django.shortcuts import render
from django.views.generic import TemplateView
# Create your views here.
class LandingView(TemplateView):
template_name = 'home.html'
dsts/urls
from django.contrib import admin
from django.urls import path
from dashboard.views import LandingView
urlpatterns = [
path('admin/', admin.site.urls),
path('', LandingView.as_view(), name='home')
]
And that's it!
Now you can use the following commands to start the application and begin the development of your django-stimulus-turbolinks application!
Build!
npm run build
Start it!
python manage.py runserver
Roundup
Whoop whoop! You did it. You created an application that is built on django, stimulus, and turbolinks. I hope this tutorial was helpful and you learned something.
Top comments (7)
After you make the build, you will not have static available because you stopped the server. You need to manually redo the url in the base template this is not a very convenient way
You are correct. I will update this after I am finished with my thesis :)
I have read this. I was really hoping to see you make a navigation bar with links or anything that will show that it's fast.
Because it seems We're back to square 1.
That is a valid point. In fact, I have a couple of views in my thesis application. I think I will add another page and add a link to show the fast navigation! Thank you for your Feedback :)
That's great, I'll be waiting.
And I'll happily remind you later :)
There's nothing terrible about that.
this was rather a sarcastic line. I still love react!