This tutorial is out of date and no longer maintained.
This is your gateway to having the VueJS’s sweetness in a Django app. Later articles will dig deeper as I cover routing and state management.
What this article will cover:
After each step, there is a link to the codebase as it should be after that step.
Sometime back I challenged myself to build a Django app and use VueJS for its frontend. There are a lot of Laravel and VueJS tutorials out there and even within Scotch. Actually, VueJS caught the attention of Taylor Otwell, the creator of Laravel, so much so that he personally endorses it.
I however struggled to find a good resource on combining Django and VueJS. Here’s a tutorial that would have been an answer to my questions back then. A testament to my learnings so far.
It is said that simplicity is a prerequisite for reliability. Evan You must have been meditating on this saying when he thought of creating VueJS. During the past year, it’s become a favorite among developers. Compared to JS frameworks like Angular and React, many agree that VueJS’s learning curve is the most gentle. This means it is easier to get the fundamentals rapidly. VueJS is backed by Laravel and JSFiddle and is at over 65,000 GitHub stars (as at the writing of this post).
This Hello World example on JSFiddle is the best place to start. There are several resources that dig deeper to show you the building blocks of VueJS. The VueJS docs’ API and guide as well as these tutorials set you up on the road to success.
Django is a Python framework that promises to be “the web framework for perfectionists with deadlines”. Django uses the MVC (Model, View, Controller) pattern dabbed MTV (Model, Template, View).
To get started open the terminal (I’m assuming that you have python
and pip
installed) then run pip install django
. It is best that you do this in a virtual environment. Proceed with the following commands:
- django-admin startproject newapp
- cd newapp
- python manage.py startapp journal
Doing this will give you the following folder structure:
To run the server simply run python manage.py runserver
. Accessing http://localhost:8000/
on your browser will give you such a page:
Don’t mind the warning highlighted in red. They relate to the database which we are not concerned about for this tutorial.
Quit the server with CONTROL+C
and let’s create our first view, shall we?
Open the views.py
file in the journal directory and these two lines.
def index(request):
return render(request, 'index.html')
Create a templates
folder in the same level as the journal
folder and create a file: index.html
in that folder. We’ll start with a very simple index.html
. Here’s what I have:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Journal</title>
</head>
<body>
<p>Welcome to My Journal</p>
</body>
</html>
We then need to map this view to a URL in order to call it. Simply put, we want to see this index.html
when we get to a specific URL in our browser. This is done by editing the newapp/urls.py
. You’ll notice that line 19 to 21 is a list called urlpatterns
. Line 20 tells us that the URL route admin
is registered. This means that we have an admin dashboard ready for you out-of-the-box with Django. More about that later. If you are curious here is a link to the docs covering this.
Since we want to display the index.html as the page served at http://localhost:8000/
we’ll import the index function within journal/views.py
and map it to the URL route /
.
We do this by adding two lines to the newapp/urls.py
:
from journal.views import index
above urlpatterns
and
url(r'^$', index, name='index'),
within urlpatterns
.
Your urls.py will now look like this:
from django.conf.urls import url
from django.contrib import admin
from journal.views import index
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', index, name='index'),
]
Lastly, our view needs to know where the template index is located. Open the settings.py
within newapp
and search for TEMPLATES
. Within it, you’ll notice a key in the object called 'DIRS'
whose value is an empty list. Enter os.path.join(BASE_DIR, "templates"),
so that that line reads:
'DIRS': [os.path.join(BASE_DIR, "templates"),]
That’s about it.
Back to the terminal run python manage.py runserver
access http://localhost:8000/
on your browser and voila your page is displayed.
That was easy, right? We just added 4 lines of code, edited one line in the settings.py
, and added one file the index.html
.
This section is entitled “Jinja templates in Django” so let’s see what that means. Jinja2 is a full-featured template engine for Python which is both beautiful and powerful. I plan to tackle template inheritance
and context handling
for now.
This is a journal and for the sake of simplicity in this tutorial, we’ll display a list of three days (titles with the words: “Day 1”, “Day 2”, and “Day 3”). To do this edit views.py
file to include:
context = {
'days': [1, 2, 3],
}
just before the return
statement. Make sure your indentation is right. Change index.html
to days.html
then add context
as an additional argument in the render
method. The file should look like this eventually:
from django.shortcuts import render
# Create your views here.
def index(request):
context = {
'days': [1, 2, 3],
}
return render(request, 'days.html', context)
In the spirit of modularity, I’ll split index.html into masterpage.html
and days.html
.
Copy the lines above the HTML paragraph tag (<p>
) and paste into a new file masterpage.html
in the templates folder. We’ll add a Jinja2 block in the next line: {% block content %} {% endblock %}
and finally add HTML </body>
and </html>
closing tags. The file will look like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Journal</title>
</head>
<body>
{% block content %} {% endblock %}
</body>
</html>
Next, create another file days.html
still in the templates folder. Start the file with {% extends 'masterpage.html' %}
. Open a block content by adding this line {% block content %}
and then copy the HTML paragraph tag (<p>
) from the index.html
and paste it into the next line. Close the block by adding {% endblock %}
. Your days.html
file should end up like this:
{% extends 'masterpage.html' %}
{% block content %}
<p>Welcome to My Journal</p>
{% endblock %}
To confirm everything is a-okay, let’s update the views.py
by changing the index.html
in " "
(quotes) to days.html
. Running the server at this point should not show any visual change.
Take time to understand how index.html
is now split into two files: masterpage.html
and days.html
.
Let’s now display the days. One simply adds the following code snippet immediately after the HTML paragraph tag (<p>
):
<ul>
{% for day in days %}
<li><h4> Day {{ day }}</h4></li>
{% endfor %}
</ul>
The curly braces: {{
and }}
we use here are used to bind the dynamic data to the HTML list tag (<li>
) enabling us to iterate through the list of days in views.py
context to display the list of days.
Reloading the page will show you this:
At this point, we can delete the index.html
in the templates folder.
So far, we have seen how the TV (Template-View) in the MTV (Model-Template-View) of Django is done. We can now incorporate VueJS.
It is easy to get started with VueJS. We’ll tweak the JSFiddle link I shared earlier to have it working in our view.
First off, we’ll import vuejs
by including:
<script src="https://unpkg.com/vue"></script>
in the head of masterpage.html
.
Next, we’ll go to days.html
and sandwich the HTML paragraph tag (<p>
) and unordered-list tag (<ul>
) into a div of id=app
. The name app
is open to your discretion. Just remember to replace app
hereon with the name you decide to use.
We’ll add the HTML script tag here to define a client-side script (JavaScript). Most times the script is placed in another .js
file and imported to the html file
but having it here will help us better see how the DOM will relate to the script. The script in this case will be:
<script>
new Vue({
delimiters: ['[[', ']]'],
el: '#app',
data: {
title: 'Welcome to My Journal'
}
})
</script>
The curly braces: {{
and }}
we used earlier are called interpolation delimiters. By default, VueJS’s interpolation delimiters are the same as that of Jinja templates: {{
and }}
. Good news, we can change the delimiters to anything we want and that’s what I have done in the line delimiters: ['[[', ']]']
. I want the text in the paragraph tag (<p>
) to be interpolated from VueJS so let’s replace the text with [[ title ]]
. The page days.html
will now read:
{% extends 'masterpage.html' %}
{% block content %}
<div id="app">
<p> [[ title ]] </p>
<ul>
{% for day in days %}
<li>
<h4> Day {{ day }}</h4>
</li>
{% endfor %}
</ul>
</div>
<script>
new Vue({
delimiters: ['[[', ']]'],
el: '#app',
data: {
title: 'Welcome to My Journal'
}
})
</script>
{% endblock %}
We can go ahead and replace the days
from context data to be populated from the script. We do this by adding days
to the data
object: days: [1,2,3]
. We’ll change the HTML unordered-list tag (<ul>
) to:
<ul>
<li v-for="day in days">
<h4> Day [[ day ]]</h4>
</li>
</ul>
Again the entire file looks like this:
{% extends 'masterpage.html' %}
{% block content %}
<div id="app">
<p> [[ title ]] </p>
<ul>
<li v-for="day in days">
<h4> Day [[ day ]]</h4>
</li>
</ul>
</div>
<script>
new Vue({
delimiters: ['[[', ']]'],
el: '#app',
data: {
title: 'Welcome to My Journal',
days: [1,2,3]
}
})
</script>
{% endblock %}
Reload the page in your browser. At this point, the contents of the page are being rendered by VueJS. On Google Chrome, you can install VueJS devtools
here and you’ll be able to see the data within the components.
We have created a simple Django app touching on the TV (Template-View) of the MTV (Model-Template-View) of Django. We’ve seen how we extend our views using Jinja2 template engine. We then concluded by replacing the context data with data from VueJS.
In the next articles, we shall take develop the app further by adding CRUD functions to this app. CRUD means Create, Read, Update, and Delete, thereby allowing the user to do these functions to their journal entries. Secondly, because we are using VueJS and Django; we shall have contextual data from the DB directly consumed from the View Layer in Django as well as expose this data to API endpoints to be consumed by a separate VueJS application. This is to present you with an alternative way to build your app.
Actually we can have the data v-for
reading from the context-data in views.py
like this: <li v-for="day in {{days}}">
thereby making the data.html
read:
{% extends 'masterpage.html' %}
{% block content %}
<div id="app">
<p> [[ title ]] </p>
<ul>
<li v-for="day in {{days}}">
<h4> Day [[ day ]]</h4>
</li>
</ul>
</div>
<script>
new Vue({
delimiters: ['[[', ']]'],
el: '#app',
data: {
title: 'Welcome to My Journal'
}
})
</script>
{% endblock %}
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!