DEV Community

loading...

How to build a django app with stimulus and turbolinks

webspaceadam profile image Adam ・6 min read

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

At this point we start to work in our virtual environment. The perfect moment for the installation of Django.

pipenv install django
Enter fullscreen mode Exit fullscreen mode

When the installation is finished, we want to start a new django project:

django-admin startproject dsts . 
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'
                        ]
                    }
                }
            }
        ]
    }
}
Enter fullscreen mode Exit fullscreen mode

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"
  },
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

index.css

.content {
    max-width: 300px;
    margin: auto;
  }

p {
    font-size: 32px;
}
Enter fullscreen mode Exit fullscreen mode

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}!`
  }
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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')
]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Start it!

python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

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.

Discussion

pic
Editor guide
Collapse
butonix profile image
Butonix

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

Collapse
webspaceadam profile image
Adam Author

You are correct. I will update this after I am finished with my thesis :)

Collapse
smyja profile image
Smyja

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.

Collapse
webspaceadam profile image
Adam Author

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 :)

Collapse
smyja profile image
Smyja

That's great, I'll be waiting.

And I'll happily remind you later :)

Collapse
dmwyatt profile image
Dustin Wyatt

And they had a standalone react-frontend built with create-react-app (terrible, I know).

There's nothing terrible about that.

Collapse
webspaceadam profile image
Adam Author

this was rather a sarcastic line. I still love react!