Integrate charts in Django admin Interface.

Neeraj Kumar
3 min readDec 15, 2019

Django admin is a great interface and powerful features for managing data. It shows models that are registered in the admin.py file of each Django app.

Django admin has full customization for developers and current many libraries available’s on GitHub that can change the interface of admin with extra features by some easy installation step.

I want to make charts in Django admin with custom model fields value using chart.js

Setup:

Firstly I created new model in Django project.

models.py file

from django.db import models

MALE, FEMALE = range(2)
GENDER = (
(MALE, 'MALE'),
(FEMALE, 'FEMALE')
)

CHINESE, SPANISH, ENGLISH, FRENCH, HINDI, ARABIC, RUSSIAN = range(7)
LANGUAGES = (
(CHINESE, 'CHINESE'),
(SPANISH, 'SPANISH'),
(ENGLISH, 'ENGLISH'),
(FRENCH, 'FRENCH'),
(HINDI, 'HINDI'),
(ARABIC, 'ARABIC'),
(RUSSIAN, 'RUSSIAN'),
)

class Student(models.Model):
full_name = models.CharField('Full Name', max_length=50)
gender = models.PositiveSmallIntegerField('Gender', choices=GENDER, default=MALE)
language = models.PositiveSmallIntegerField('Language', choices=LANGUAGES, default=ENGLISH)
grades = models.CharField('Grades', max_length=2)

def __str__(self):
return self.full_name

class Meta:
verbose_name = ('Student')

Above is student Django model and I’ll make the graph of gender, language and grades fields in the admin changelist page.

Now we need to create ModelAdmin for register this model in Django admin and we’ll customize changelist template from this admin view.

admin.py file

from django.contrib import admin
from main.models import Student
class StudentAdmin(admin.ModelAdmin):
list_display = ('full_name', 'langugae', 'grades', 'gender')
list_filter = ('langugae', 'gender', 'grades')
save_as = True
save_on_top = True
change_list_template = 'change_list_graph.html'


admin.site.register(Student, StudentAdmin)

I customized default ModelAdmin features here and Django admin has features to customize templates of admin interface, So I did override changelist template.

https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-admin-templates

I created a new template that name is change_list_graph.html and save in templates directory of the app.

change_list_graph.html file

{% extends "admin/change_list.html" %}
{% load staticfiles %}
{% block extrahead %}
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.min.js"></script>
<script>
var randomColorGenerator = function () {
return '#' + (Math.random().toString(16) + '0000000').slice(2, 8);
};
var options = {
responsive: true,
maintainAspectRatio: true,
legend: {
position: 'left'
},
title: {
display: true
},
animation: {
animateScale: true,
animateRotate: true
}
};
window.onload = function () {
var ctx = document.getElementById("gender-chart");
{% regroup cl.queryset|dictsort:"gender" by get_gender_display as gender_list %}
var lineChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [{% for gender in gender_list %}'{{ gender.grouper }}',{% endfor %}],
datasets: [{
data: [{% for gender in gender_list %}'{{ gender.list|length }}',{% endfor %}],
backgroundColor: [{% for gender in gender_list %}randomColorGenerator(),{% endfor %}]
}]
},
options: options
});
ctx = document.getElementById("language-chart");
{% regroup cl.queryset|dictsort:"grades" by grades as grades_list %}
lineChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [{% for grade in grades_list %}'{{ grade.grouper }}',{% endfor %}],
datasets: [{
data: [{% for grade in grades_list %}'{{ grade.list|length }}',{% endfor %}],
backgroundColor: [{% for grades in grades_list %}randomColorGenerator(),{% endfor %}]
}]
}, options: options
});
ctx = document.getElementById("grades-chart");
{% regroup cl.queryset|dictsort:"language" by get_language_display as language_list %}
lineChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [{% for language in language_list %}'{{ language.grouper }}',{% endfor %}],
datasets: [{
data: [{% for language in language_list %}'{{ language.list|length }}',{% endfor %}],
backgroundColor: [{% for language` in language_list %}randomColorGenerator(),{% endfor %}]
}]
}, options: options
});
}
</script>
{% endblock %}
{% block content %}
<h1> Graphs </h1>
<hr>
<div class="row">
<div class="col-sm-4">
<canvas id="gender-chart" style="width: 100px !important;"></canvas>
</div>
<div class="col-sm-4">
<canvas id="language-chart" style="width: 100px !important;"></canvas>
</div>
<div class="col-sm-4">
<canvas id="grades-chart" style="width: 100px !important;"></canvas>
</div>
</div>
{{ block.super }}
{% endblock %}

In HTML code there is {% regroup %} templatetags of Django default. It sorted and regroup data based on a field.

{% regroup cl.queryset|dictsort:”language” by get_language_display as language_list %}
So here “language” used for sorting and get_language_display used for grouping data.

--

--