April 2020
The purpose of this tutorial is to demonstrate how to customize the Django admin index page and add a chart easily using the library django-chartJs.
You can find the source code in this repository
For this tutorial will use a model Product
class Product(models.Model):
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
refShop = models.ForeignKey(Shop, db_index=True,on_delete=models.CASCADE)
title = models.TextField(max_length=65)
price = models.FloatField(default=0)
withEndDate = models.BooleanField(default=False)
endDate = models.DateField(blank=True,null=True)
description = models.CharField(max_length=65, default='', null=True, blank=True)
createdAt = models.DateTimeField(auto_now_add=True)
updatedAt = models.DateTimeField(auto_now=True)
available = models.BooleanField(default=True)
And our goal will be to display a custom admin index page with a graph showing the number of new product per month.

To do that we will tell Django that we want to use a custom index html file. As we did on this tutorial , we add a new line index_template in our Admin class with the path to our new file
from django.contrib.admin import AdminSite
class MyAdminSite(AdminSite):
login_template = 'backoffice/templates/admin/login.html'
index_template = 'backoffice/templates/admin/index.html'
Then we will override the default Django index.html file by copying it into our new path
cp ../../../environnements/genericenv/lib/python3.7/site-packages/django/contrib/admin/templates/admin/index.html backoffice/templates/admin/
To display a chart we will use the django-chartjs librarie so we include it in our requirements.txt file
django==3
django-chartjs
And then add it to our INSTALLED_APPS of our settings.py file
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'backoffice',
'chartjs',
]
Now in the {% block content %} of the index.html file we will add our code for displaying a graph
{% block content %}
<canvas id="myChart" width="50" height="10"></canvas>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.10.0.min.js"></script>
<script type="text/javascript" src="{% static 'js/Chart.min.js' %}"></script>
<script type="text/javascript">
$.get('{% url "new_product_per_month" %}', function(data) {
var ctx = $("#myChart").get(0).getContext("2d");
new Chart(ctx, {
type: 'line', data: data
});
});
</script>
<div id="content-main">
To get the data for the graph to being displayed we call a view with the instruction .get(‘{% url “new_product_per_month” %}’
So we need to define this view in our views.py file
from chartjs.views.lines import BaseLineChartView
from django.db.models import Count
from django.views.generic import TemplateView
class NewProductMonthChartJSONView(BaseLineChartView):
def get_labels(self):
"""Return 7 labels for the x-axis."""
return ["January", "February", "March", "April", "Mai", "June", "July","August","September","October","November","December"]
def get_providers(self):
"""Return names of datasets."""
return ["New products"]
def get_data(self):
"""Return 3 datasets to plot."""
#get user per month
from django.db.models import Count
from django.db.models.functions import TruncMonth
from backoffice.models import Product
import datetime
date = datetime.date.today()
items = Product.objects.filter(createdAt__year=date.year).annotate(month=TruncMonth('createdAt')).values(
'month').annotate(total=Count('id'))
totalMonth={}
#initialisation
for i in range(1, 13):
totalMonth[i]='0'
for item in items:
month = item["month"]
totalMonth[month.month]= item["total"]
return [[int(totalMonth.get(1)), int(totalMonth.get(2)), int(totalMonth.get(3)), int(totalMonth.get(4)), int(totalMonth.get(5)), int(totalMonth.get(6)), int(totalMonth.get(7)),int(totalMonth.get(8))
,int(totalMonth.get(9)),int(totalMonth.get(10)),int(totalMonth.get(11)),int(totalMonth.get(12))]]
line_chart = TemplateView.as_view(template_name='line_chart.html')
line_chart_json = NewProductMonthChartJSONView.as_view()
This view defines 3 methods :
get_labels | Return 12 labels for the x-axis. |
get_providers | Return names of datasets. |
get_data | Return datasets to plot ie our new product per month count |
Before providing data to our chart, we need to calculate the values
We make a query which will count the product created per month for the current year
items = Product.objects.filter(createdAt__year=date.year).annotate(month=TruncMonth('createdAt')).values(
'month').annotate(total=Count('id'))
Then we can send back a JSON which will be rendered by the graph. To get more details about the django-chartjs don’t hesitate to read the library documentation.