Skip to main content

Django API and Chart.JS

Learn how to showcase charts with Django & Chart.JS

Django is a robust web framework that enables the swift and effortless development of complex web applications. It is commonly used for creating data-centric web apps that display information through charts and graphs.

This guide will explore how to integrate Django with Plotly to create an interactive chart that visualizes data in a web application.

Chart.js is a data visualization library that enables you to generate interactive, high-quality graphs and charts in Python, R, and other programming languages. With Chart.js, you can produce various types of visualizations, including line charts, scatter plots, bar charts, box plots, and more.

Chart.js primary feature is its ability to create interactive visualizations, allowing you to add hover-over tooltips, zoom in and out, pan across the graph, and click on data points to display more detailed information. These interactive features make it easier to explore and understand your data.

Chart.js also offers a wide range of customization options, allowing you to modify colors, fonts, and layouts to produce charts that match your specific needs. Furthermore, Chart.js graphs can be easily embedded in web apps or shared with others by exporting them to various file formats like PNG, SVG, or PDF.

In this tutorial, we will use the Django material dashboard and modify its homepage to create sales charts using data from Django models, the data will be served using Django API Generator, a tool that generates secure APIs on top of Django REST framework.

To get started, we will create a new Django project and establish a new application to serve as the homepage for our program.

Then, we will create a model to store our sales data. Then we will add Django API Generator to our Django project and we will create a view to serve this data to the front-end. Finally, using Chart.js, we will generate interactive line charts, bar charts, and pie charts that will display data sourced from the sales model.

Django API and Chart.JS - Tutorial provided by AppSeed.

✅ Setting up Django

To set up a new Django project, start by creating a new folder using the "mkdir" command followed by the desired name of the folder. Then, change into the newly created directory using the "cd" command followed by the name of the folder.

$ mkdir django_api_and_chartjs
$ cd django_api_and_chartjs
django_api_and_chartjs$

Afterward, create a new virtual environment within the folder using the virtualenv module bundled with Python, using the command "virtualenv venv". To activate the virtual environment, run the command source venv/bin/activate on MacOS/Linux or ./venv/Scripts/activate on Windows.

On MacOS/Linux

django_api_and_chartjs$ virtualenv venv
django_api_and_chartjs$ source venv/bin/activate
(venv) django_api_and_chartjs$

On Windows

django_api_and_chartjs$ virtualenv venv
django_api_and_chartjs$ .\venv\Scripts\activate
(venv) django_api_and_chartjs$

Next, install the necessary packages including Django and material-design, and create a new Django project.

(venv) django_api_and_chartjs$ pip install django django-admin-material-dashboard django-api-generator
(venv) django_api_and_chartjs$ django-admin startproject core .

To create a new Django application, use the command

(venv) django_api_and_chartjs$ python manage.py startapp home

Make the following changes in the core/settings.py file allowing our Django project to recognize the home application just created and django-admin-material-dashboard. Additionally, we will be setting the default directory for template files, static files and also the route user login redirects to

# core/settings.py
import os # <-- NEW import
...
INSTALLED_APPS = [
"home",
"admin_material.apps.AdminMaterialDashboardConfig",
...
]
...
UI_TEMPLATES = os.path.join(BASE_DIR, "templates") # <-- NEW

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [UI_TEMPLATES], # <-- UPDATED
...
}
]
...
STATIC_URL = "/static/"
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
LOGIN_REDIRECT_URL = '/'
...
  • Next, modify the core/urls.py file to add routes to the newly created application and the material dashboard.
# core/urls.py
from django.urls import include, path <-- UPDATED add path

urlpatterns = [
path('', include('home.urls')),
path("admin/", admin.site.urls),
path("", include('admin_material.urls'))
]

In the home/views.py file, create a view of the homepage of the web application using the index function, which returns the rendered pages/index.html template. Note pages/index.html exists in django-admin-material-dashboard, soon we will be adding our own index.html file.

# home/views.py
...
def index(request):

# Page from the theme
return render(request, 'pages/index.html')

Create a new file named urls.py inside the home folder and add a route to the index view.

# home/urls.py
from django.urls import path

from . import views

urlpatterns = [
path('', views.index, name='index'),
]

Finally, run the Django server from the terminal using the python manage.py runserver command and access the homepage in your browser using the URL http://127.0.0.1:8000. This shows the installed material dashboard theme.

(venv) django_api_and_chartjs$ python manage.py runserver

Now that our Django application is running, we will be creating a model to store data in our database.

✅ Creating Sales Model

To display dynamic sales data in our Django and Chart.js web applications, we first need to create a model to store the data in our database. This can be achieved using Django's Object-Relational Mapper (ORM) to define the structure of the database.

Define Sales table structure

Open the home/models.py file and make the necessary changes to create a new Sales model

# home/models.py
from django.db import models

class Sales(models.Model):
product = models.CharField(max_length=255)
price = models.IntegerField()
currency = models.CharField(
choices=(('USD', 'USD'), ('EUR', 'EUR')),
default='USD',
max_length=3
)
country = models.CharField(max_length=50)
purchase_date = models.DateTimeField()

def __str__(self):
return self.product

class Meta:
verbose_name = 'Sale'
verbose_name_plural = 'Sales'

Adding Sales data to the database

To access the database from the admin panel, we need to register it. Open home/admin.py and make the following changes:

# home/admin.py
...
from .models import Sales # <-- NEW import

admin.site.register(Sales)
  • Run the command from your terminal to create Django default tables and the Sales table.
(venv) django_api_and_chartjs$ python manage.py makemigrations
(venv) django_api_and_chartjs$ python manage.py migrate
  • Next step we will be creating a superuser, this will enable us to have access to the admin panel
(venv) django_api_and_chartjs$ python manage.py createsuperuser
(venv) django_api_and_chartjs$ python manage.py runserver

The first command will prompt you to enter a username, email (optional), and password for the superuser. Once you've entered this information, the superuser will be created and you can use the credentials to log in to the admin panel at http://127.0.0.1:8000/admin/ after you have executed the second command and the Django server is running.

Django Admin material dashboard

Once you have accessed the admin panel, you can click on the "Add sale" button to add new sales data to the database. This data will then be available for us to retrieve and display dynamically in our web application using Chart.js.

Django Admin material dashboard

Django API Generator Installation and Setup

The Django API generator is used to create API routes for our Django models, which allows us to perform Create-Read-Update-Delete (CRUD) operations on that model. It is built on top of the Django REST framework.

Installing `Django API Generator

Django API Generator was installed earlier when we were installing packages needed for this tutorial. To install the package separately use the command pip install django-api-generator

Setup `Django API Generator

  • Update core/settings.py file to make use of the package
# core/settings.py
...
INSTALLED_APPS = [
'django_api_gen', # Django API GENERATOR # <-- NEW
'rest_framework', # Include DRF # <-- NEW
'rest_framework.authtoken', # Include DRF Auth # <-- NEW
]
...
API_GENERATOR = {
# pattern:
# API_SLUG -> Import_PATH
'sales' : "home.models.Sales",
}

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
}
...

API_GENERATOR is used to keep a mapping of API url and the model the route should point to

  • Run the command to create tables used by the Django REST framework
(venv) django_api_and_chartjs$ python manage.py makemigrations
(venv) django_api_and_chartjs$ python manage.py migrate
  • The next command will generate API routes that can be queried for data or to make changes to entries in our database
(venv) django_api_and_chartjs$ python manage.py generate-api

After running this command, a new folder named api is autogenerated with files that define the API routes and view.

  • Now, we will be adding urls to make use of the routes created by the python manage.py generate-api command. Open core/urls.py and make the changes
# core/urls.py
...
from django.urls import include, path
from rest_framework.authtoken.views import obtain_auth_token

urlpatterns = [
...
path('api/', include('api.urls')),
path('login/jwt/', view=obtain_auth_token),
]

Now if we head to http://127.0.0.1/api/sales we will be able to see the view showing data gotten from the database, methods allowed and the status of the request. From this page, we can send POST requests to add data to the database, and PUT requests to update data already stored in the database.

Workspace 1_021 resized

Workspace 1_022 resized

With the API set up, we can now proceed to create charts on our Django application using Chart.js and leveraging data from the API.

✅ Using Chart.Js with Django

There are several ways Chart.js can be used in a web development project. It can be done using CDN and using npm to install the chart.js package. Check chartjs installation guide for directions to install chart.js

Integrating Chart.js with Django

We will be using the CDN method for this tutorial. Create a base template inside your templates folder named base.html and add the code

<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block javascript%}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.2.1/chart.min.js" integrity="sha512-v3ygConQmvH0QehvQa6gSvTE2VdBZ6wkLOlmK7Mcy2mZ0ZF9saNbbk19QeaoTHdWIEiTlWmrwAL4hS8ElnGFbA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
{% endblock %}
<title>Document</title>
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>

The {% block javascript %} contains a script to the chart.js cdn and this will provide the Classes needed to add charts to the web application.

Note: django-admin-material-dashboard already uses Chart.js, without defining our script, we can make use of it.

✅ Creating Dynamic Charts

We will be using external javascript to create the charts, and using javascript fetch API to query the API for data.

Copy index.html file from venv/lib/python3.10/site-packages/admin_material/templates/pages and paste it into templates/pages. Now our index.html page for the application will be served by the file in templates/pages

Extracting the data from the API

  • Create a folder called static in the root directory of your project. Inside the folder create another folder js and create the file getModelData.js and add the following
// static/js/getModelData.js
const salesData = {
country: [],
countrySales: [],
month: [],
monthlySales: [],
};

async function getData() {
const [product, price, month, country] = [[], [], [], []];

await fetch('/api/sales')
.then((response) => response.json())
.then((data) => {
const monthNames = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
]
data.data.map((sale) => {
product.push(sale.product);
price.push(sale.price);
month.push(monthNames[new Date(sale.purchase_date).getMonth()]);
country.push(sale.country);
})
})
.catch((err) => {
console.log(err);
})
return [product, price, month, country];
}

const data = getData();
data.then(data => {
[product, price, months, countries] = data;

countries.forEach((country, index) => {
countryIndex = salesData.country.indexOf(country);
if (countryIndex > -1) {
salesData.countrySales[countryIndex] = salesData.countrySales[countryIndex] + price[index];
} else {
salesData.country.push(country);
salesData.countrySales.push(price[index]);
}
})

months.forEach((month, index) => {
monthIndex = salesData.month.indexOf(month);
if (monthIndex > -1) {
salesData.monthlySales[monthIndex] = salesData.monthlySales[monthIndex] + price[index];
} else {
salesData.month.push(month);
salesData.monthlySales.push(price[index]);
}
})
});

Because the labels and data used in Chartjs is an array, we had to perform some preprocessing on the data so we can produce proper charts from the data.

country and countrySales in the salesData object hold the countries from the database and the total sales from that country respectively. Using their index to match them together. month and monthlySales takes account of the months from the database and the total sales in each month respectively.

getData function returns an array of arrays, with each array corresponding to product, price, month and country being extracted from the data returned by the API.

The code after the function, processes the data from the getData function further to make it useful for visualization.

Creating a Bar chart from data

The bar chart will show total sales by country. The salesData object earlier contained country and countrySales. country will serve as the label and countrySales as the data. Since django_admin_material_dashboard already uses Chartjs, no additional setting is required to display charts on templates.

  • Create a file named drawChart.js in static/js/ and add the code
// static/js/drawChart.js
function barChart() {
const ctx = document.getElementById("chart-bars").getContext("2d");
new Chart(ctx, {
type: "bar",
data: {
labels: salesData.country, // <-- data from model
datasets: [{
label: "Sales",
borderWidth: 0,
borderRadius: 4,
borderSkipped: false,
backgroundColor: "rgba(255, 255, 255, .8)",
data: salesData.countrySales, // <-- data from model
maxBarThickness: 30
}, ],
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
}
},
scales: {
y: {
grid: {
drawBorder: false,
display: true,
drawTicks: false,
color: 'rgba(255, 255, 255, .2)'
},
ticks: {
suggestedMin: 0,
suggestedMax: 500,
beginAtZero: true,
padding: 10,
font: {
size: 14,
weight: 300,
family: "Roboto",
style: 'normal',
lineHeight: 2
},
color: "#fff"
},
},
x: {
grid: {
drawBorder: false,
display: true,
drawOnChartArea: true,
drawTicks: false,
borderDash: [5, 5],
color: 'rgba(255, 255, 255, .2)'
},
ticks: {
display: true,
color: '#f8f9fa',
padding: 10,
font: {
size: 14,
weight: 300,
family: "Roboto",
style: 'normal',
lineHeight: 2
},
}
},
},
},
});
}

Now, we will be making changes to index.html that we copied earlier to display the chart from the barChart function. At the bottom of templates/index.html inside the {% block scripts %} tag. Delete the code for the default static charts being displayed and add the following.

<!-- templates/index.html -->
{% block scripts %}
<script src={% static 'js/getModelData.js' %}></script>
<script src={% static 'js/drawChart.js' %}></script>
<script>
setTimeout(() => {
barChart();
}, 500);
</script>
{% endblock scripts %}

By adding the getModelData.js and drawChart.js scripts, we have access to the functions and variables created in them.

The barChart function is called inside the setTimeout function to allow the data from the API to be loaded since the fetch API is an asynschronous function and it returns a promise. By doing this, the promise can get resolved and the data passed to the barChart function.

Creating a Line chart from data

The line chart will show the sales trend by month. The salesData object earlier contained month and monthlySales. month will serve as the label and monthlySales as the data.

Add the following to static/drawChart.js

function lineChart() {
const ctx2 = document.getElementById("chart-line").getContext("2d");

new Chart(ctx2, {
type: "line",
data: {
labels: salesData.month,
datasets: [{
label: "Mobile apps",
tension: 0,
borderWidth: 0,
pointRadius: 5,
pointBackgroundColor: "rgba(255, 255, 255, .8)",
pointBorderColor: "transparent",
borderColor: "rgba(255, 255, 255, .8)",
borderColor: "rgba(255, 255, 255, .8)",
borderWidth: 4,
backgroundColor: "transparent",
fill: true,
data: salesData.monthlySales,
maxBarThickness: 6

}],
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
}
},
interaction: {
intersect: false,
mode: 'index',
},
scales: {
y: {
grid: {
drawBorder: false,
display: true,
drawOnChartArea: true,
drawTicks: false,
borderDash: [5, 5],
color: 'rgba(255, 255, 255, .2)'
},
ticks: {
display: true,
color: '#f8f9fa',
padding: 10,
font: {
size: 14,
weight: 300,
family: "Roboto",
style: 'normal',
lineHeight: 2
},
}
},
x: {
grid: {
drawBorder: false,
display: false,
drawOnChartArea: false,
drawTicks: false,
borderDash: [5, 5]
},
ticks: {
display: true,
color: '#f8f9fa',
padding: 10,
font: {
size: 14,
weight: 300,
family: "Roboto",
style: 'normal',
lineHeight: 2
},
}
},
},
},
});
}

After creating the function, now we need to call the function to make the chart show on the dashboard. Make the following changes to templates/index.html

<!-- templates/index.html -->
...
<script>
setTimeout(() => {
barChart();
lineChart(); // <-- NEW added
}, 500);
</script>

Creating a Pie chart from data

The pie chart will use the same data as the bar chart, just displaying it differently.

Add the function below to static/drawChart.js

function pieChart() {
const ctx3 = document.getElementById("chart-pie").getContext("2d");

new Chart(ctx3, {
type: "pie",
data: {
labels: salesData.country,
datasets: [{
label: 'My First Dataset',
data: salesData.countrySales,
backgroundColor: [
'rgb(255, 99, 132)',
'rgb(54, 162, 235)',
'rgb(255, 205, 86)'
],
hoverOffset: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
labels: {
color: '#fff'
},
display: true,
}
},
},
});
}

The ctx3 variable for our pieChart function is pointing to the chart-pie id, and that id does not exist on our template. Head to line 125 and make the changes

<!-- templates/index.html -->
...
<div class="chart">
<canvas id="chart-pie" class="chart-canvas" height="170"></canvas>
</div>
...
<script>
setTimeout(() => {
barChart();
lineChart();
pieChart(); // <-- NEW added
}, 500);
</script>

By changing the canvas id to chart-pie our function points to the right id and the chart can be displayed on the homepage.

Open your browser and open http://127.0.0.1 and you can see the charts being created using data from the API

Workspace 1_024 resized

✅ Conclusion

In this tutorial, we've explored how to use Django, Django API generator and Chart.js together to build a web application that displays data in an interactive chart. We started by setting up a new Django project and app, creating a model to store our sales data, and populating the database with sample data.

Next, we registered the database in the Django admin panel, created a superuser, and used the admin panel to add more data to the database.

We then generated an API for our sales model using the django-api-generator package and tested the API to ensure it was working properly.

Finally, we integrated Chart.js into our Django application and created a dynamic chart that displays the sales data fetched from the API. We also added user interactivity to the chart by allowing the user to filter data by date range.

Overall, this tutorial demonstrates how Django, Django API generator and Chart.js can be used together to build powerful and interactive web applications.

✅ Resources