Passing Django Database Queryset to Highcharts via JSON - python

First time poster, long time reader. I've spend quite awhile looking for an answer to this, which makes me think its something fundamental I'm missing.
I'm trying to pull data held in a database table and pass it through for display in a Highcharts plot. I'm not getting any errors from Django or by the client when inspecting source.
Using: Django 1.7 and Python 3.4
The views.py:
#unit/views.py
from django.http import JsonResponse
from django.shortcuts import render
from unit.analysis_funcs import ChartData
def chart_data_json(request):
data = {}
data['chart_data'] = ChartData.get_data()
return JsonResponse(data, safe = True)
def plot(request):
return render(request, 'unit/data_plot.html', {})
The get_data() function:
#unit/analysis_funcs.py
from unit.models import CheckValve
class ChartData(object):
def get_data():
data = {'serial_numbers': [], 'mass': []}
valves = CheckValve.objects.all()
for unit in valves:
data['serial_numbers'].append(unit.serial_number)
data['mass'].append(unit.mass)
return data
The template:
<!-- templates/unit/data_plot.html -->
{% extends "base.html" %}
{% block extrahead %}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
{% endblock %}
{% block rootcontainer %}
<div id="container" style="width:100%; height:400px;"></div>
{% endblock %}
{% block overwrite %}
<!-- Overwrite the base.html jQuery load and put in head for Highcharts to work -->
{% endblock %}
{% block extrajs %}
<script>
$(document).ready(function() {
var options = {
chart: {
renderTo: 'container',
type: 'line'
},
series: [{}]
};
var ChartDataURL = "{% url 'chart_data_json' %}";
$.getJSON('ChartDataURL', function(data) {
options.xAxis.categories = data['chart_data']['serial_numbers'];
options.series[0].name = 'Serial Numbers';
options.series[0].data = data['chart_data']['mass'];
var chart = new Highcharts.Chart(options);
});
});
</script>
{% endblock %}
Finally the urls:
from unit import views, graphs
urlpatterns = patterns('',
url(r'^chart_data_json/', views.chart_data_json, name = 'chart_data_json'),
url(r'^plot/', views.plot, name = 'plot'),
)
Everything seems to run, but the Highchart plot doesn't render. I think its in how I'm moving the JSON data from the view.py to the template.html, but after so long staring at it I'm going cross-eyed.
Any help would be awesome!

I finally got my plotting working. I found this approach here. Thanks to Harrison for posting his method!
My new views.py based on the above approach:
def plot(request, chartID = 'chart_ID', chart_type = 'line', chart_height = 500):
data = ChartData.check_valve_data()
chart = {"renderTo": chartID, "type": chart_type, "height": chart_height,}
title = {"text": 'Check Valve Data'}
xAxis = {"title": {"text": 'Serial Number'}, "categories": data['serial numbers']}
yAxis = {"title": {"text": 'Data'}}
series = [
{"name": 'Mass (kg)', "data": data['mass']},
{"name": 'Pressure Drop (psid)', "data": data['pressure drop']},
{"name": 'Cracking Pressure (psid)', "data": data['cracking pressure']}
]
return render(request, 'unit/data_plot.html', {'chartID': chartID, 'chart': chart,
'series': series, 'title': title,
'xAxis': xAxis, 'yAxis': yAxis})
Quick function for pulling database objects and passing the data:
class ChartData(object):
def check_valve_data():
data = {'serial numbers': [], 'mass': [],
'pressure drop': [], 'cracking pressure': [], 'reseat pressure': []}
valves = CheckValve.objects.all()
for unit in valves:
data['serial numbers'].append(unit.serial_number)
data['mass'].append(unit.mass)
data['cracking pressure'].append(unit.cracking_pressure)
data['pressure drop'].append(unit.pressure_drop)
data['reseat pressure'].append(unit.reseat_pressure)
return data
The key to Harrison's method is a mapping script to translate the Highcharts js to Python template variables:
{% extends "base.html" %}
{% block extrahead %}
<!-- Load in jQuery and HighCharts -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
{% endblock %}
{% block heading %}
<h1 align="center">Analysis</h1>
{% endblock %}
{% block content %}
<div id={{ chartID|safe }} class="chart" style="height:100px; width:100%"></div>
{% endblock %}
{% block overwrite %}
<!-- Overwrite the base.html jQuery load and put in head for Highcharts to work -->
{% endblock %}
{% block extrajs %}
<!-- Maps the Python template context variables from views.py to the Highchart js variables -->
<script>
var chart_id = {{ chartID|safe }}
var chart = {{ chart|safe }}
var title = {{ title|safe }}
var xAxis = {{ xAxis|safe }}
var yAxis = {{ yAxis|safe }}
var series = {{ series|safe }}
</script>
<!-- Highchart js. Variable map shown above -->
<script>
$(document).ready(function() {
$(chart_id).highcharts({
chart: chart,
title: title,
xAxis: xAxis,
yAxis: yAxis,
series: series
});
});
</script>
{% endblock %}
Everything works and displays correctly now!

Related

django ckeditor - call data from rich text editor

Does anyone know if it is possible to call data from the richtext editor in the admin panel?
My views.py looks like this:
def post_detail(request, slug):
posting = post.objects.get(slug=slug)
try:
if posting.slug == 'dividend_stocks_list':
data = pd.DataFrame(stocks(request))
allData=[]
for i in range(data.shape[0]):
temp = data.iloc[i]
allData.append(dict(temp))
context_posting = {
'title': posting.title,
'date': posting.date_added,
'intro': posting.intro,
'body': posting.body,
'data': allData
}
except:
context_posting = {
'title': posting.title,
'date': posting.date_added,
'intro': posting.intro,
'body': posting.body,
}
return render(request, 'post_detail.html', context_posting)
next is the html
{% block content %}
{% load humanize %}
<h1 class="title">{{ title }}</h1>
<small>Posted at {{ date }}</small>
<br/>
<br/>
<hr/>
<div>{{ intro | safe }}</div>
<hr/>
<div>{{ body | safe }}</div>
{% endblock %}
{% block js %}
{% endblock %}
I would like to type in the rich text editor
blablabla
{{ data | safe }}
blablabla
But till now I have not figured out how to do that.
Do you have any idea?

Django redirect doesnt work after posting JSON data

Return redirect doesn't work in an else statement after receiving json data. The same redirect works in an other if statement. In the terminal I can see the GET request for the url I want to redirect to, that is why I found this strange.The print statement works perfectly in else, only redirect fails. My code so far:
views.py (please let me know if the other views are necessary to answer the question)
def data_type_error_handling(request):
'''handles all the possible choices after data_type_errors '''
if '_skip' in request.POST:
return redirect('data_validation')
elif 'first_load' in request.session or '_refresh' in request.POST or request.method == 'GET':
print("data_load vagy refresh")
error_list = request.session['error_list']
errors = json.dumps(error_list, indent=4, sort_keys=True, default=str)
if 'first_load' in request.session:
del request.session['first_load']
return render(request, "upload/data-type-correction.html",
{"error_list": errors})
else:
raw_data = request.body.decode('utf-8')
data = json.loads(raw_data)
print(data)
return redirect('data_validation')
def data_validation(request):
return render(request, "upload/data-validation.html")
return redirect('data_validation') works in the first if statement, but not in else, it stays on the same page where I clicked on the button.
urls.py
from django.urls import path
from . import views
urlpatterns=[
path('data-upload', views.data_upload, name='data-upload'),
path('upload-failed', views.data_upload, name='upload-failed'),
path('upload-successful', views.data_upload, name='upload-successful'),
path('data-type-correction', views.data_type_error_handling, name ='data-type-correction'),
path('data-validation', views.data_validation, name ='data_validation'),
]
data-type-correction.html
{% extends "base.html" %}
{% block title %} Data type error correction {% endblock title %}
{% block content %}
<h1>Data type errors</h1>
<h3 id="data-type-error-h3">There are data type errors in your submission. Please change string characters to numbers in the Amount column.</h3>
<input type="submit" class="btn-back-correct" id="btn-back-to-upload" value="Back" onclick="history.go(-1)" />
<div id="main-container">
<button type="submit" class="btn-submit-correct" id="btn-repost-data-errors" name="_reload">Load corrected data</button>
<div id="datatype-error-container"></div>
<form action="" method="post">
<ul id="datatype-action-container">
{%csrf_token%}
<li><input type="submit" class="btn-submit-correct" id="btn-dismiss-data-errors" value="Skip this data" name="_skip" onclick="return confirm('Are you sure you do not need this data?');"></li>
<li><input type="submit" class="btn-submit-correct" id="btn-refresh-data-errors" value="Refresh error list" name="_refresh"></li>
</ul>
</form>
<!--handsontable-->
<script>
var errors = {{ error_list|safe }}
console.log(errors)
function log (event) {console.log(event)}
var container = document.getElementById('datatype-error-container');
var settings = {
data: errors,
rowHeaders: true,
colHeaders: true,
filters: true,
dropdownMenu: true,
contextMenu: true,
width: '75.66%',
height: 500,
minRows: 1,
afterChange: log.bind(this, 'afterChange'),
afterRemoveRow: log.bind(this, 'removeRow'),
afterRemoveCol: log.bind(this, 'removeCol'),
afterCreateRow: log.bind(this, 'createRow'),
afterCreateCol: log.bind(this, 'createCol'),
columns: [
{
data: 0,
type: 'text',
width: 210,
allowInsertRow: true
},
{
data: 1,
width: 210,
type: 'text',
},
{
data: 2,
width: 210,
type: 'text',
},
{
data: 3,
width: 210,
},
],
licenseKey: 'non-commercial-and-evaluation',
colHeaders: [
'CID',
'Product',
'Account',
'Amount'
]
};
var hot = new Handsontable(container, settings);
</script>
<script src="../../static/app/scripts/fetchData.js"></script>
</div>
{% endblock content %}
data-validation.html
{% extends "base.html" %}
{% block title %} Data validation {% endblock title %}
{% block content %}
<h1>Data validation output goes here</h1>
{% endblock content %}

can not export variable from admin.py to overriden template in django

good night, i have overriden a template in django (change_list.html) to show chart.js charts in django admin page following the tutorial in this tutorial,bute when i get to the part when have to replace the hard coded data with the variable chart_data from teh admin.py file and pas it to the overriden template change_list.html,nothing happens and the table shows with all values in 1. what could be happening, i have not found any information about how variables are passed from admin.py to the overriden template html files. Here is the code
class ReporteActividadUsuariosAdmin(admin.ModelAdmin):
list_display = ['nombre','apellidos','carnet','cliente','cantidad_de_prestamos']
ordering = ['-cantidad_de_prestamos']
def changelist_view(self, request, extra_context=None):
chart_data = (
ReporteActividadUsuarios.objects.annotate(Count("cantidad_de_prestamos"))
.values("nombre","apellidos")
.annotate(y=Count("cantidad_de_prestamos"))
#.group_by("cantidad_de_prestamos")
#.order_by("-carnet")
)
# Serialize and attach the chart data to the template context
as_json = json.dumps(list(chart_data), cls=DjangoJSONEncoder)
extra_context = extra_context or {"chart_data": as_json}
# Call the superclass changelist_view to render the page
return super().changelist_view(request, extra_context=extra_context)
def has_add_permission(self, request):
return False
and the overriden template file change_list.html is as follows:
{% extends "admin/change_list.html" %}
{% load static %}
{% block content %}
{% block extrahead %}
{{ block.super }}
<link rel="stylesheet" href="{% static '/asset/css/Chart.min.css' %}" />
<script src="{% static '/asset/js/admin/Chart.bundle.min.js' %}"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const ctx = document.getElementById('myChart').getContext('2d');
const chartData = {{ chart_data | safe }};
//const chartData = [1,7,12,8,2] ;
// Render the chart
var myPieChart = new Chart(ctx, {
type: 'bar',
data: {
datasets: [{
data: chartData,
borderColor: '#00443436' ,
backgroundColor: ['#df0000','lightgreen','orange','lightblue','lightyellow'],
}],
// These labels appear in the legend and in the tooltips when hovering different arcs
labels: [
'MARIA DEL CARMEN MUZIO ZARRANZ',
' LAY MI RODRIGUEZ GUILBEAUX',
'REINALDO LAZARO LASTRE LABRADA',
'SISSI CARIDAD RODRIGUEZ PERAZA',
'AUSTIN LLERANDI PEREZ'
]
},
options: {
//animation: { animateRotate: true,} ,
}
});
}) ;
</script>
{% endblock %}
<h3> Usuarios Mas Activos </h3>
<div style="width: 23%;">
<canvas style="margin-bottom: 0px; width: 65%; height: 60%;"
id="myChart"></canvas>
</div>
<!-- Render the rest of the ChangeList view by calling block.super -->
{{ block.super }}
{% endblock %}
thanks very much in advance,

request.session isn't saved or is somehow modified

It seems that my request.session isn't saved or is somehow modified in other ways, despite using request.session.modified = True after changing the value.
Here is the debug output:
This should run first.
This should run second.
I have set main category to 2 (Shoes)
Main category is 1 (Books)
The code below should display a different ModelForm based on selected category, however when I select, for instance, Books, ShoesModelForm is displayed and vice-versa. This currently works as follows: whenever a value in a combobox is changed, two AJAX requests are fired. First one calls a view (load_categories) that renders another if a category has children, otherwise returns an HttpResponse which stops attaching the listener. Second one calls a view (load_modelform) that renders a specific ModelForm if selected category is root node (main category).
mappings = {
'1': BookProductForm,
'2': ShoesProductForm
}
def load_categories(request):
print("This should run first.")
category_id = request.GET.get('category')
request.session['category'] = category_id
request.session.modified = True
if Category.objects.get(id=category_id).is_root_node():
request.session['main_category'] = category_id
request.session.modified = True
print(f"I have set main category to {request.session['main_category']} ({Category.objects.get(id=category_id).name})")
subcategories = Category.objects.get(id=category_id).get_children()
if subcategories:
return render(request, 'products/category_dropdown_list_options.html', {'subcategories': subcategories})
return HttpResponse('leaf_node')
def load_modelform(request):
print("This should run second.")
main_category = request.session['main_category']
print(f"Main category is {main_category} ({Category.objects.get(id=main_category).name})")
form = mappings[main_category]
return render(request, 'products/category_modelform.html', {'form': form})
#login_required
def product_create_view(request):
if request.method == 'POST':
category = request.session.get('main_category')
create_product_form = mappings[category](request.POST)
if create_product_form.is_valid():
create_product_form.save()
return render(request, 'products/product_create.html', {
'categories': Category.objects.filter(parent=None)
})
What might be going on here?
#EDIT:
I'm including my template with jQuery code that contains Ajax requests:
{% extends 'pages/base.html' %}
{% load static %}
{% block cssfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'products/css/create.css' %}">
{% endblock %}
{% block content %}
<h1>Create a product</h1>
<div class='modelform'>
<form method='POST' id='productForm' data-products-url="{% url 'products:ajax_load_categories' %}" data-modelform-url="{% url 'products:ajax_load_modelform' %}">
{% csrf_token %}
<div class='categories'>
<label>Category</label>
<select>
{% for category in categories %}
<option value="{{ category.pk }}">{{ category.name }}</option>
{% endfor %}
</select>
</div>
<div class='the-rest'>
{{ form.non_field_errors }}
{% for field in form %}
{% ifnotequal field.name 'category' %}
{{ field.label_tag }} {{ field }}
{{ field.errors }}
{% endifnotequal %}
{% endfor %}
</div>
<input type="submit" name="" value="Submit">
</form>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
var $r_ = function() {
var url = $("#productForm").attr("data-products-url");
var categoryId = $(this).val();
var toRemove = $(this).nextAll('select');
$.ajax({
url: url,
data: {
'category': categoryId
},
success: function (data) {
if (data != 'leaf_node') {
toRemove.remove();
$(".categories").append(data);
}
else {
toRemove.remove();
}
}
});
var url2 = $('#productForm').attr('data-modelform-url');
setTimeout(function() {
$.ajax({
url: url2,
data: {
'category': categoryId
},
success: function (data) {
if (data != 'dont_change_modelform') {
$('.the-rest').empty();
$('.the-rest').append(data);
}
}
});
}, 100);
}
$(document).on('change', 'select', $r_);
</script>
{% endblock %}

django-nvd3 load_chart tag evaluates to False in output HTML and no chart is displayed

I'm trying to implement a pieChart using django-nvd3. However, the output html of {% load_chart charttype chartdata chartcontainer extra %} evaluates to False. Resultantly (most likely) the chart fails to appear. Below is the view.py, django template and html output.
View.py
def results(request, nlm_id, time):
journal = Journal.objects.get(nlm_id = nlm_id)
stats = return_week(nlm_id, time, PLATFORMS)
chartdata = {'x': PLATFORMS, 'y': stats}
charttype = "pieChart"
chartcontainer = 'piechart_container'
data = {
'charttype': charttype,
'chartdata': chartdata,
'chartcontainer': chartcontainer,
'extra': {
'x_is_date': False,
'x_axis_format': '',
'tag_script_js': True,
'jquery_on_ready': True,
}
}
return render(request, 'journals/results.html', {'journal': journal,
'stats': stats, 'time': time, 'data': data})
Template
{% extends "base.html" %}
{% load staticfiles %}
{% load nvd3_tags %}
<head>
{% block style %}
{{ block.super }}
{% include_chart_jscss %}
{% load_chart charttype chartdata chartcontainer extra %}
{% endblock %}
</head>
<body>
{% block content %}
{% include_container chartcontainer 400 600 %}
{% endblock %}
</body>
Output HTML
<html>
<head>
...
<script>False</script>
</head>
<body>
<div id=""><svg style="width:600px;height:400px;"></svg></div>
</body>
</html>
A solution could be to pass the variables charttype, chartdata, chartcontainer, and extra directly like this:
context = {
'charttype': charttype,
'chartdata': chartdata,
'chartcontainer': chartcontainer,
'extra': {
'x_is_date': False,
'x_axis_format': '',
'tag_script_js': True,
'jquery_on_ready': False,
},
'journal': journal,
'stats': stats,
'time': time,
}
return render(request, 'journals/results.html', context)
I faced similar problem and I fixed it when I changed {% load_chart charttype chartdata chartcontainer extra %}
to {% load_chart data.charttype data.chartdata data.chartcontainer data.extra %}
and similarly {% include_container chartcontainer 400 600 %} to {% include_container data.chartcontainer 400 600 %}
You can wrap your load_chart in an if statement which checks that there is chartdata, eg:
{% if chartdata %}
{% load_chart charttype chartdata chartcontainer extra %}
{% endif %}

Categories