Django, Ajax, Popover & Chartjs

Amiay Narayan
4 min readMay 19, 2021

--

In my coding universe(mcu), I keep trying to solve problems. To be honest, however, the problems are not always very novel or unique. In fact these problems do not demand a new set of tools to be created. We don’t have to re-invent the wheels; wheels are present, we just have to cleverly assemble them. Ofcourse, we will be creating a django app that will show a bootstrap popover whose content will be a chart/graph which will be fetched using ajax call; but I would propose to focus on a more bigger picture that I am trying to paint here — how we can use different tools available to us and “engineer” our way to a solution.

Let us get right into it. I presume a basic understanding of how to get started with a django app on your machine. If not, I recommend going throught their documentation, they’ve done a pretty good job. Having set up the virtual env and the project, let us create a new app :

// on the command line
$django-admin createapp mcu
// in settings.py
INSTALLED_APPS=[
...
'mcu.apps.McuConfig',
...
]
TEMPLATES = [{
...
DIRS: [os.path.join(BASE_DIR, 'templates')],
...
}]

We will create views that will be responsible to show a home page and the initial content. We will dynamically change the content of this home page, by making ajax requests to other views(DataView) that we are going to define here as well. Let’s write some code:

from random import randintfrom django.shortcuts import render
from django.http import JsonResponse
# Create your views here.def PopoverView(request):
"""
Displays the home page and sends the initial content.
"""
init_text = "Before software can be reusable it first has to be
usable
"
context = {
"text" : init_text,
}
return render(request, 'mcu/home.html', context)
def DataView(request):
"""
Sends a list of random numbers in JSON format
"""
context = {
"number" : [randint(0,100) for _ in range(10)],
}
return JsonResponse(context)
def QuoteView(request, serial):
"""
Handles the content of component_two column
"""
text_one = "Good programmers write code that human can
understand.
"
text_two = "First, solve the problem. Then, write the code."
text_thr = "Fix the cause, not the symptom."
choices = [ text_one, text_two, text_thr ]
context = {
"text": l[randint(0,len(l) - 1)],
}
return JsonResponse(context)

Let us now define the routes :

from django.contrib import admin
from django.urls import path
from ajax.views import PopoverView, DataView, QuoteView
urlpatterns = [
path('admin/', admin.site.urls),
path('', PopoverView, name='popover'),
path('data/', DataView, name='data'),
path('data/<int:serial>/', QuoteView, name='quote'),
]

We are done with the backend section, let us just set up our frontend. Frontend uses Jinja2 templating library.

$ cd mcu
$ mkdir -p templates/mcu/
$ touch templates/mcu/base.html
$ touch templates/mcu/home.html
// you can directly use the file manager, I like to use terminal on Ubuntu to manage files.

Now base.html file is present on my GitHub repo (yes, I prefer keeping to the point). Nothing too fancy, just plain-old jinja2 templates. The actual ‘meat of the matter’ — home.html:

{% extends 'mcu/base.html' %}{% block body %}<div class="container">
<div class="row">
<h2> AJAX Demonstration </h2>
</div>
<div class="row">
<div class=" col-6 component_one">
<div class="new" data-toggle="popover" title="Keep guessing" >
Ever Changing Plot
</div>
</div>
<div class="col-6 component_two">
<p id="guess_me">{{text}}</p>
<button class="btn btn-info" id="change_btn">
Change
</button>
</div>
</div>
</div>
{% endblock %}

To use Twitter-bootstrap we have to add data-toggle=”popover” to the desired element. The above create two columns, first columns has ‘.new’ element hovering on which should show my a popover with a graph in it. Additionally, the right column contains some text which will change on button click. First things first, how to get the popover working — jQuery!

{% block java_script %}$('[data-toggle="popover"]').popover({
html: true,
trigger: 'hover',
content: '<canvas id="myChart" width="400" height="400">
</canvas>',
placement: 'bottom',
}).on('shown.bs.popover', function() {
$.ajax({
url : "{% url 'data' %}",
success: function(data){
new Chart($('#myChart'), {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: ["January", "February", "March", "April",
"May", "June", "July"],
datasets: [{
label: "Label",
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: data.number,
}]
},
// Configuration options go here
options: {}
});
}
});
});
{% endblock %}

.popover() method makes sure the popover is fired when we cause the ‘trigger’ even to happen(here we have ‘hover’). Popover also provides the javascript options ‘shown.bs.popover’. This is fired after the popover over shows up. So why not make an ajax call in here? Yes that is what we have done. And up on successful response to the request, we receive that data and render the data (list of random numbers) in the form a chart using Chartjs charting library. Yes that is it! You made it! If things went good this output should look as below:

Screenshot of the working app

We have another functionality as well, the text on the right side should change on button click. I leave this small task to the reader, to evaluate his/her understanding of the concept. Hope you have fun doing this.

With this I come to the end of the blog. Hopefully, I was able demonstrate the concept of putting things together to get things done. Please leave a comment/feedback, I would really appreaciate. Also, mention if you want me to make a youtube video as well. If I have enough requests, I will be more than happy to do so. Hope I was able to provide value in one way or other. See you next time…

Resources:
GitHub Repository: https://github.com/amiaynara/Dj-popver-ajax (Note: names of variable are different than present here)
Quotes: https://dzone.com/articles/best-programming-jokes-amp-quotes
Chartjs: https://www.chartjs.org/docs/latest/#creating-a-chart

https://unsplash.com/photos/QLBYlclmgFo [Thanks Nathoniel Tetteh]

--

--

Responses (1)