Please wait...

How to make charts in django admin interface?

by in Django

Django Charts

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

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.

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

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

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 also feature to customize templates of admin. So I did override changelist template.

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

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

change_list_graph.html:

{% extends "admin/change_list.html" %}
{% load static %}
{% 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 format that is {% regroup %} templatetags of Django default. It sorted data into based on field and also regroup data according to field.  

{% regroup cl.queryset|dictsort:"language" by get_langugae_display as language_list %}

This is the simplest way to render graph in Django admin interface.

 


Download code from GitHub.com