Skip to content

Django Vue.js Integration Tutorial

Michael Bukachi edited this page May 24, 2019 · 11 revisions

Introduction

This tutorial answers the question, "How do I integrate Vue.js with Django?" Since you are reading this tutorial, I hope you know that Django is a Python web framework built for rapid web development. If not, and you probably think that we are talking about the movie :), then I would suggest reading about it here before proceeding with this tutorial.

Vue.js is a progressive framework for building user interfaces. If you are not familiar with it, you can read about it here.

Now that you are familiar with both Django and Vue.js, we can begin.

Django Setup

Before we proceed we need to install a couple of dependencies. So so run this command in your terminal:

pip install django django-webpack-loader

Once you've installed Django successfully, we need to create a new Django project with the following command:

django-admin startproject my_django_vue

This creates a new directory called “my_django_vue” with the basic Django directory and structures:

├── manage.py
    └── my_django_vue
        ├── __init__.py
        ├── settings.py
        ├── urls.py
        └── wsgi.py

Navigate into the "my_django_vue" directory and run:

$ python manage.py migrate

This will create the necessary tables in your database. By default, Django uses sqlite3 as its database. This can be easily be changed in the settings.py file, however, that is outside the scope of this tutorial.

After running the migrate command, this should be your new directory structure:

├── db.sqlite3
├── manage.py
└── my_django_vue
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

Now, launch the development server with:

python manage.py runserver

You should see the following output if Django and the database are setup correctly:

Performing system checks...

System check identified no issues (0 silenced).
June 13, 2017 - 22:03:03
Django version 1.11.2, using settings 'my_django_vue.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Point your browser at http://127.0.0.1:8000 and you should see the Django “It worked!” page. Back in your terminal, kill the server by pressing CONTROL-C.

Set up your Django app

Now let's create our app with:

$ python manage.py startapp myapp

Your project structure should now look like this:

├── db.sqlite3
├── manage.py
├── myapp
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
└── my_django_vue
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

We need to create an entry point for our app. Start by creating a directory called templates in the myapp directory. Then create an index.html file in the newly created directory. Paste the following snippet in the new created html file:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Django Vue</title>
</head>
<body>
</body>
</html>

We need to link the newly created html file with Django. Open up urls.py. If you more than one, open the project-scoped urls.py not that app-scoped in the myapp directory. Edit it so that it appears as so:

from django.conf.urls import url
from django.views.generic import TemplateView

urlpatterns = [
    url(r'^$', TemplateView.as_view(template_name='index.html'), name='index'),
]

Vue.js setup

Now we'll initialize our JavaScript dependencies. Run this in the root of your Django project:

npm init

Follow the prompts, entering the appropriate values. This will create a 'package.json' file which will hold all our JavaScript dependencies.

To add the dependencies, run:

npm install --save-dev axios bootstrap-sass jquery node-sass sass-loader vue webpack webpack-cli  @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/runtime babel-loader babel-preset-es2015 babel-preset-stage-0 css-loader style-loader vue-loader vue-hot-reload-api vue-template-compiler webpack-bundle-tracker

This will create a node_modules folder in the root of Django project. You can also check the package.json and you should see something close to this:

{
  "name": "my_django_vue",
  "version": "1.0.0",
  "description": "An app to integrate Django and Vue.js",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "python",
    "javascript",
    "webpack",
    "django"
  ],
  "author": "michael bukachi",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.3.4",
    "@babel/plugin-transform-runtime": "^7.3.4",
    "@babel/preset-env": "^7.3.4",
    "@babel/runtime": "^7.3.4",
    "axios": "^0.16.2",
    "babel-loader": "^8.0.5",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "bootstrap-sass": "^3.4.1",
    "css-loader": "^0.23.0",
    "jquery": "^3.1.0",
    "lodash": "^4.17.11",
    "node-sass": "^4.11.0",
    "sass-loader": "^6.0.5",
    "style-loader": "^0.13.0",
    "vue": "^2.6.8",
    "vue-hot-reload-api": "^1.2.0",
    "vue-loader": "^15.7.0",
    "vue-template-compiler": "^2.6.8",
    "webpack": "^4.29.6",
    "webpack-bundle-tracker": "^0.4.2-beta",
    "webpack-cli": "^3.2.3"
  }
}

Now create the folders assets/js/components. If you running a unix based OS, you can do so by running:

mkdir -p assets/js/components

In the js folder, create a new JavaScript file called index.js and paste the following snippet:

window.$ = window.jQuery = require('jquery');
require('bootstrap-sass');

import Vue from 'vue';
import Demo from "./components/Demo.vue";

window.Vue = Vue;
const app = new Vue({
    el: '#app',
    components: {
        Demo
    }
});

window.$ = window.jQuery = require('jquery'); will make the jQuery library available to our code.

require('bootstrap-sass'); loads bootstrap.

import Vue from 'vue'; loads the Vue.js library.


import Demo from "./components/Demo.vue";

window.Vue = Vue;
const app = new Vue({
    el: '#app',
    components: {
        Demo
    }
});

Loads a Vue component (which we are yet to create) and integrates into our application.

Now create a file called Demo.vue in the `components directory. Past the following in that file:

<template>
    <div>
        <p>This is just a demo.</p>
    </div>
</template>

<script>
</script>

<style>
</style>

If you have worked with Vue.js before, you should be familiar with above syntax. We basically creating a Vue component which we loaded earlier in the index.js

Integration

Now we need to integrate the Vue.js app with Django. Go to the settings.py and add 'webpack_loader' to your INSTALLED_APPS list like so:

   ...
   'webpack_loader'
]

Also, in the TEMPLATES variable, replace DIRS: [], with DIRS: [os.path.join(BASE_DIR, 'myapp/templates')],

At the bottom of the file add:

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'assets'),
)


WEBPACK_LOADER = {
    'DEFAULT': {
        'BUNDLE_DIR_NAME': 'bundles/',
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
    }
}

Here, we are adding the assets folder we created earlier as one of directories Django should check for static files. We are also initializing webpack_loader settings, which will direct the loader to the directory of the assets.

Now go to the index.html file we create earlier and modify it so that it appears as follows:

{% load render_bundle from webpack_loader %}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Django Vue</title>
</head>
<body>
    <div id="app">
        <demo></demo>
    </div>
    {% render_bundle 'main' %}
</body>
</html>

{% load render_bundle from webpack_loader %} loads the loader into the template. <div id="app"> is where the Vue.js app will be initialized. <demo></demo> is where our Demo.vue component will be loaded. Finally, {% render_bundle 'main' %} will load the build output of webpack into our template.

Now that we have integrated Vue.js with Django, we need to finalize the configurations for webpack. Start by creating webpack.config.js in the root of your project directory. Paste the following snippet into that file:

const path = require('path');
const webpack = require('webpack');
const BundleTracker = require('webpack-bundle-tracker');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
    mode: 'development',
    context: __dirname,
    entry: './assets/js/index',
    output: {
        path: path.resolve('./assets/bundles/'),
        filename: 'app.js'
    },

    plugins: [
        new BundleTracker({filename: './webpack-stats.json'}),
        new VueLoaderPlugin(),
    ],

    module: {
        rules:  [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
            },
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            }
        ],
    },
    resolve: {
        alias: {vue: 'vue/dist/vue.js'}
    },

};

Let's breakdown this configuration file.

entry: './assets/js/index',
output: {
    path: path.resolve('./assets/bundles/'),
    filename: 'app.js'
},

Here, we've set the entry point and also set filename and directory for the output of the webpack build.

module: {
        rules:  [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
            },
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            }
        ],
    }
}

Here, we configuring the loaders to be used by webpack. The extensions of the files are checked and the appropriate loaders are used.

resolve: {
    alias: {vue: 'vue/dist/vue.js'}
},

This ensures that you can use templates in your code. Without this, you'll most likely end up with a blank section wherever you want to render your components.

Now we create .babelrc in your root directory and paste the following in it:

{
  "presets": [
    "@babel/env"
  ],
  "plugins": [
    "@babel/transform-runtime"
  ]
}

Since Vue.js uses es6 JavaScript syntax, babel needs to convert that syntax to common JavaScript so that it is compatible with most browsers.

Now we need our assets into one file build file. Just run ./node_modules/.bin/webpack from the root directory. You should see an output similar to this:

Hash: 6edac5f580eef23e229e
Version: webpack 4.29.6
Time: 1572ms
Built at: 03/06/2019 6:53:18 PM
 Asset     Size  Chunks             Chunk Names
app.js  244 KiB       0  [emitted]  main
Entrypoint main = app.js
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
[3] ./assets/js/components/Demo.vue?vue&type=template&id=c6620ff8& + 1 modules 589 bytes {0} [built]
    |    2 modules
[7] ./assets/js/index.js 478 bytes {0} [built]
    + 10 hidden modules

This tells us that webpack manage to build your assets successfully. Now, launch the development server with:

python manage.py runserver

And point your browser http://127.0.0.1:8000 and you should see “This is just a demo.”

If you see this message, you have successfully integrated Django with Vue.js. This is just a simple demo. You can do a lot more and make complex web applications.

Note The webpack configurations should not be used in a production environment. Checkout out this site in order to configure your webpack for production.

Feel free to raise any issues or ask questions if you need further elaboration.

If you want to learn how to build an uptime and incident status page with Django and VueJS, then check out this comprehensive course. It includes web sockets, celery, authentication and a lot more!

References

http://owaislone.org/blog/webpack-plus-reactjs-and-django/