How can I make chart day to day objects count in Django? - django

My question is I need to make a dashboard page. In that, I need to make a chart on day to day created objects by the specific user in Django like the image below.
Also, I need to know how to save data for this like charts.

There are lots of options if you want to create charts. Most of them are JS and/or Ajax which you can include in the template page. Try this Google Charts which I believe is the simplest way to get things up and running,
https://developers.google.com/chart/interactive/docs/gallery/piechart
You can use the parameters from the context dictionary to generate a dynamic graph.

1 From views.py Send the Value of the data (ie the number of Problems solved) through the context Dictionary.
ex: views.py
def index(request):
context = {"problems_solved" : calculated_value}
return render(request, "results.html", context)
in the Template HTML do the following ,
results.html:
{% extends "base.htm" %}
{% load static %}
{% block title %}
results
{% endblock %}
{% block head %}
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
var solved = {{problems_solved}};
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['day', 'problems solved'],
['prob solved', solved ]
]);
var options = {
title: 'Profile progress Report: '
};
var chart = new google.visualization.PieChart(document.getElementById('piechart'));
chart.draw(data, options);
}
</script>
{% endblock %}
{% block body %}
<div id="piechart" style="width: 600px; height: 500px;">
{% endblock %}
If you are looking it to be generated everyday dynamically then you need to append values based with date to the context dictionary and execute the form generation everytime the page gets loaded

Related

How do I render all the objects of a child model belonging to a particular object of the parent model on click?

Suppose there are two models Lists and Tasks where 'Lists' have one-to-many relationship with 'Tasks'.
All the objects of the Lists model are rendered on the page like this:
HTML
<div class="grid-container">
{% for list in lists %} <!--lists is context for Lists.objects.all() -->
<div class="grid-item" id="{{ list.id }}" onclick="showTasks( {{ list.id }} )">
{{ list.name }}
</div>
{% endfor %}
</div>
<dialog id="tasks">
</dialog>
JavaScript
<script>
function showTasks(listid){
document.getElementById("tasks").show();
}
</script>
Now I want to render all the tasks_set (all the objects of 'Tasks') related to a particular object of 'Lists' in that dialog with id="tasks".
As it can be seen in the above snippet, I thought of doing it by passing list.id as a parameter to the JavaScript function but couldn't figure out beyond it. How can I achieve it?
Solution 1:
Building on Iain's comment some code. I think it is easiest if you use jQuery so load it in the section of your html template, e.g.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
Then you need a view that returns the required tasks data
def tasks_view(request):
list_id = request.GET.get('listid') # fetch the id of the list
tasks = Lists.objects.get(pk=list_id).tasks.all() # get your tasks
data = {'tasks': render_to_string('tasks.html', {'tasks': tasks})} # pre render the data
return JsonResponse(data)
A remark about the view: You can of course also return the raw Json data. However, in your case I think it is easier to create a small sub-template (tasks.html in the example) and use render_to_string to get the html code you can simply add to your base html page. Don't forget to add the view to your urls.
An example task.html just for the completeness:
<ul>
{% for task in tasks %}
<li>{{ task }}</li>
{% endfor %}
</ul>
Then send an Ajax request to the view (tasks_view) when clicked.
<script>
function showTasks(listid){
$.ajax({
url: '/tasks/', // url of the view created above
data: {
'listid': listid // Your list id
},
data_type: 'html', // as we are receiving a html template
success: function(data){
$('#tasks').append(data.tasks); // append the html code to the dialog
$('#tasks').show();
}
});
}
</script>
Solution 2
In case you do not want to use Ajax and do not mind rendering all your tasks on loading the template you can also create a for the tasks of each list and show them on demand. For this iterate through your lists:
{% for list in lists %}
<dialog id="list-{{ list.id }}">
<ul>
{% for task in list.tasks.all %}
<li>{{ task }}</li>
{% endfor %}
</ul>
</dialog>
{% endfor %}
As you can see you can access the m2m field 'tasks' of each Lists object with list.tasks.all (no ()!). And each has got an individual id.
And then just show and hide the dialogs (just as an example w/o jQuery in case you are reluctant to use it):
<script>
function showTasks(listid){
// Close all dialogs
var all_dialogs = document.getElementsByTagName('dialog');
for (i = 0; i < all_dialogs.length; i++){
all_dialogs[i].removeAttribute('open');
}
// Open the required dialog
var dialog = document.getElementById("list-" + listid);
dialog.setAttribute('open','open');
};
</script>

Django endless pagination on scroll in case of overflowed container

I have the following Django template:
<div id = 'test'>
<form>
<ul id = 'dialog_list_container'>
{% include page_template %}
{% block js %}
{{ block.super }}
<script src="/static/js/el-pagination.js"></script>
<script src="/static/js/el-pagination_on_scroll.js">
</script>
<script>
$("#test").endlessPaginate({
paginateOnScroll: true,
paginateOnScrollMargin: 100
});
</script>
{% endblock %}
</ul>
<div class="ajax_loader"></div>
</form>
</div>
test is a scrollable element:
#test{
overflow-y: auto;
height: 500px;
}
The problem is that I have still to manually press the Show more link in the bottom of paginated list, whereas I would expect new records to be uploaded automatically as I scroll to the bottom of test. I guess, the reason is that Django's pagination on scroll triggers in those cases when browser window is scrolled.
Is there any painless way to make Django upload new records in case of a container with css overflow-y: auto attribute?
$.endlessPaginate binds to the entire page. If you want to focus on one element, you need to target that element specifically:
$("#test").endlessPaginate({
paginateOnScroll: true,
paginateOnScrollMargin: 20
});
P.S. the standard for ids (and classes) is hyphens not underscores: #dialog-list-container

Google maps not being displayed in django template

I am trying to display a google map for a django site. I have a template, roughly,
{% extends "base.html" %}
{% load staticfiles %}
{% block content %}
...
<div class="col-md-6">
<div id="map_canvas" style="width:100%;height:400px;background-color:#CCC;"></div>
</div>
...
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script>
function initialize() {
var mapCanvas = document.getElementById('map_canvas');
var mapOptions = {
center: new google.maps.LatLng(44.5403, -78.5463),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(map_canvas, map_options);
}
</script>
{% endblock%}
When I reload the webpage, I can see that a request is being made for Google's map url's , but I see no map, just a plain gray background.
i have the same problem in html code I delete <!DOCTYPE html> and it work
You just need to add the line before closing your script tag:
google.maps.event.addDomListener(window, 'load', initialize);
You can see it in the Documentation

how to access jQuery.ajax() get parameters in Django views

I recently started to learn jQuery and right now I am playing around with .ajax() function.
I cannot figure out how to access the get parameters in Django.
My code looks like:
Jquery & html:
<div id="browser">
<ul>
{% comment %}
Theres a script for each ctg. Each script fades out #astream, fades in #stream_loading and then it should display #astream with new values based on the GET param in ajax call
Prolly it wont work, but first I need to interact with the GET param in my views.py
{% endcomment %}
{% for ctg in ctgs %}
<script type="text/javascript" charset="utf-8">
(function($) {
$(document).ready(function() {
$("#stream_loading").hide()
$("#browse_{{ctg}}").click(function() {
$("#astream").fadeOut()
$("#stream_loading").fadeIn()
$.ajax({
type: "GET",
url: "/{{defo}}/?param={{ctg}}",
success: function() {
$("#stream_loading").fadeOut()
$("#astream").fadeIn()
}
});
});
});
})(jQuery);
</script>
<li><a id="browse_{{ctg}}" title="{{ctg}}">{{ctg}}</a></li>
{% endfor %}
</ul>
</div>
<div id="astream">
{{ajaxGet}} #just to see whats rendered
{% include "astream.html" %}
</div>
<div id="stream_loading">
loading stream, please wait ...
</div>
Django:
#https_off
def index(request, template='index.html'):
request.session.set_test_cookie()
path=request.META.get('PATH_INFO')
defo=path[1:path[1:].find('/')+1]
request.session['defo']=defo
defo=request.session['defo']
# build the stream sorted by -pub_date
import itertools
chained=itertools.chain(
model1.objects.order_by('-pub_date').filter(),
model2.objects.order_by('-pub_date').filter(),
)
stream=sorted(chained, key=lambda x: x.pub_date, reverse=True)
ajaxGet=request.GET.get('param','dummy')
if request.is_ajax():
template='astream.html'
ajaxGet=request.GET.get('param',False)
renderParams={'defo':defo, 'stream':stream, 'ajaxGet':ajaxGet}
return render_to_response(template, renderParams, context_instance=RequestContext(request))
Then I try to show it up in my template
{{ ajaxGet }}
But everytime is rendered as 'dummy'
In firebug I can see get requests with proper key and value.
What do I miss here?
Thanks
There is a frequent gotcha that people often fall into when doing this kind of Ajax, and that is not preventing the default action of the link/button. So your Ajax function never has a chance to fire, and the request that you're seeing in the Django code is caused by the normal page load - which is why is_ajax() is false.
Give the click handler a parameter, event, and call event.preventDefault(); at the end of the function.

Displaying a Google Chart Using Django

I have generated a variable data in Django with the following format:
data = [['100',10],['90',9],['80',8]]
and I've passed it off to my template using render_to_response:
return render_to_response('template.html', {
'data': data,
},
context_instance=RequestContext(request))
In the template header I have placed a call to Google Charts to generate a line chart:
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load('visualization', '1.0', {'packages':['corechart']});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Number');
data.addColumn('number', 'Number/10');
data.addRows( {{ data }} );
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, {width: 400, height: 240, title: "Numbers"});
}
</script>
When I do this, nothing is displayed. If I strip the strings out of data and try again, the chart appears, but obviously with no x-axis labels.
I have also tried adding the data using the arrayToDataTable function:
var data = google.visualization.arrayToDataTable([
['Number', 'Number/10'],
{% for datum in data %}
{{ datum }},
{% endfor %}],
false);
but this again fails to display any chart.
Any suggestions on how I can change one of the above, or try another approach to get the x-axis labels to appear?
You have to disable the autoescaping of your results. You can do so by adding the safe filter:
data.addRows( {{ data|safe }} );
or
{% autoescape off %}
[...]
{{ data }}
[...]
{% endautoescape %}
My advice is, if you can install additional packages, to use one of these wrappers:
http://code.google.com/p/google-chartwrapper/
https://github.com/jacobian/django-googlecharts/
I can't add more than two links yet but another one is located here: code.google.com/p/django-graphs/