grouped bar dataset in djanog template loop - django

i would like to draw a grouped bar from chart js using django which currently works fine. Actually i do manually. but i need to draw a grouped bar through for loop(data,label,background-color).
Actual
label_list=[2019,2020]
color_list=['#e75e72','#3396ff']
data_list=[[282,314,106,502,107,111],[86,350,411,340,635,809]]
datasets: [
{
label: {{label_list.0|safe}},
backgroundColor: '{{color_list.0|safe}}',
data:{{data_list.0|safe}} ,
},
{
label: {{label_list.1|safe}},
backgroundColor: '{{color_list.1|safe}}',
data: {{data_list.1|safe}} ,
},
]
i really do not have any idea to make it dynamically.
i need something like
{% for x in label_list %}
{{
label:label_list.forloop.counter[x],
background-color:color_list.forloop.counter[x],
data:data_list.forloop.counter[x]
}}//forloop.counter0,forloop.counter1
{% endfor %}
thanx in advance.

Rather than processing the values in template, why not you build the dataset in view and send it as context, like this:
datasets = list()
for label, color, data in zip(label_list, color_list, data_list):
value_dict = {
'label': label,
'backgroundColor' : color,
'data': data
}
datasets.append(value_dict)
context = {'datasets': json.dumps(datasets)} # use 'import json' on top of the file
return render('template.html', context)
Then use it directly in your template like this:
<script>
var dataset = {{ datasets }}
// rest of the code
</script>

Related

How to access custom fields in a data.home._children loop

I've added a few custom fields in lib/modules/apostrophe-custom-pages/index.js
Specifically, I've added a field for an excerpt, image Singleton for a cover image and another Singleton that will allow users to define an icon to a page.
This is how these images are defined:
{
name: 'icon',
label: 'Icon',
type: 'singleton',
widgetType: 'apostrophe-images',
options:{
limit: 1,
minSize: [200,200],
aspectRatio: [1,1],
},
controls:{
movable:false
},
image: true
},
{
name: 'coverimg',
label: 'Header Image',
type: 'singleton',
widgetType: 'apostrophe-images',
options:{
limit: 1,
minSize: [400,400],
aspectRatio: [1,1],
},
controls:{
movable:false
},
image: true
}
The cover image and the icon I can retrieve while on the page by using: {% set coverimage = apos.images.first(data.page.coverimg) or null %} ,
however, I can't reach the icon in the navigation under data.home._children like so:
{%- for tab in data.home._children -%}
{%- set iconImg = apos.images.all(tab.icon) %}
{{ apos.log(tab) }}
<li>
<a class="sidebar-main-link
{% if data.page and (apos.pages.isAncestorOf(tab, data.page) or tab._id == data.page._id) %}
active
{% endif %}
" href="{{ tab.slug }}">
<div class="icon" style="
backgroung-image: url('{{ apos.attachments.url(image.attachment, { size: 'full'}) }}') "></div>
{{ tab.title }}
</a>
</li>
{% endfor %}
This returns the standard missing.svg image
There is a new tutorial on the apostrophe documentation site which covers this issue in detail.
The short answer is that you must configure the filters option of the apostrophe-pages module to load related pages with more than just very basic information. For performance reasons, this default behavior is not a bad thing, but asking Apostrophe to load just one widget won't slow things down too much.
// in lib/modules/apostrophe-pages/index.js
module.exports = {
// other configuration, then...
filters: {
ancestors: {
children: {
areas: [ 'thumbnail' ]
}
}
}
};

ChartJS doesnt display labels provided by Jinja variable

I would like to use Flask to render a ChartJS graph. This is from my routes.py
#app.route("/graph")
def graph():
d = Eval.query.all()
labels = [i.date.strftime('%d.%m.%Y') for i in d]
data = [i.bw for i in d]
return render_template('chart.html', title='Charts', labels = labels, data = data)
I've the following code in the chart.html:
{% extends "base.html" %}
{% block content %}
<canvas id="myChart" height="400" width="800"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>
<script type="text/javascript">
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: ['16.07.2017', '23.07.2017', '30.07.2017', '06.08.2017', '13.08.2017'],
datasets: [{
label: "My First dataset",
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: {{ data }}
}]
},
options: {
responsive:false
}
});
</script>
{% endblock %}
with this code the chart is rendered with the correct labels.
Question:
However once I change the labels to
labels: {{ labels }}
the chart is not rendered at all.
I checked to make sure that the {{ labels }} expression is indeed also a list with the correct formating. Calling {{ labels }} above the script tag shows the following output in the html page:
['16.07.2017', '23.07.2017', '30.07.2017', '06.08.2017', '13.08.2017']
If you are not using safe filter special symbols would be escaped during template parsing process and would corrupt the variable value.
In the case above, final variable value without 'jinja safe' filter would be
["16.07.2017", "23.07.2017"] =>['16.07.2017','23.07.2017']
And that value (['16.07.2017','23.07.2017']) is illegal for JS and you'll be able to see the error in the browser console:
Uncaught SyntaxError: Unexpected token &
In the case above, final variable value with 'jinja safe' filter would be the same
["16.07.2017", "23.07.2017"] =>["16.07.2017", "23.07.2017"]
You can read more about escaping here.
var ctx = document.getElementById('myChart').getContext('2d');
var dates = {{labels|safe}};
var data1 = {{data|safe}}
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: dates,
datasets: [{
label: "My First dataset",
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: data1
I added the Jinja expressions as variables inside the script and now the chart renders as expected. Still not sure why ...

How to have template tags recognized in a context variable in DJango

I have a Django template that displays a link generated with template tags, and I want to send it as a context variable:
views.py:
def my_view(request):
...
link = '''Drop'''
context = {
'link': link,
}
return render(request, "my_template.html" , context)
I am trying this in my_template.html:
{{ link | safe }}
but the link is literally rendered as "{% url 'quests:drop' s.id %}"
Is there a way to have the template tags sent in the context variable recognized and executed by the template engine?
EDIT:
Why I am trying to do this is because I will actually be sending a list of buttons to the template, each with a different link and text, which will be looped through (in this example, looping through various 's' objects), and multiple views will be using the template (each view with their own button set), so the buttons are extremely context specific.
My template was becoming a spaghetti of logic to handle all the situations, and sending the buttons in the context seems like it would be much more DRY and result in a cleaner, easier to read template.
EDIT 2:
Another option that could solve the problem is if I could just pass the changing parts:
link_data = ['quests:drop','Drop']
context = {
'link_data': link_data,
}
return render(request, "my_template.html" , context)
And then the template would have:
{{link_data.1}}
However, as is, {{link_data}} doesn't render and I get the error:
Reverse for '{{ link_data.0 }}' ... not found.
You shouldn't is the answer. To achieve what are trying to do fits perfectly inline with how templates are supposed to work and you are over complicating it.
context = {
'buttons': {
'button1': {
'text': 'This is a button',
'link': reverse('quests:drop', args=[...])
},
'button2':{...}
}
}
And in the template:
{% for button in buttons %}
<a class="btn btn-primary" href={{button.link}}>{{button.text}}</a>
{% endfor %}
You could also create a Button class and use it similarly:
context = {
'buttons': [
Button('This is text', reverse('quests:drop', args=[...]),
...
],
}
Referencing to your 2nd edit:
The code in your template should look like this:
{{ link_data.1 }}
Notice the omitted '{{ }}' tags.

How do I use the Django for template tag in Dojo?

I am trying to use the "for" Django template tag in my javascript. Iam using Dojo's DataGrid to create a list of items. This is my code:
<script type="text/javascript">
require(['dojox/grid/DataGrid' , 'dojo/data/ItemFileWriteStore' , 'dojo/dom' , 'dojo/domReady!'],
function(DataGrid, ItemFileWriteStore, dom){
/*set up data store*/
var data = {
identifier: "id",
items: []
};
{% for item in items_list %}
data.items.push({ id: {{ item.url }} + '_' + {{ item.id }}, col1: {{ item.description }} });
{% endfor %}
var store = new ItemFileWriteStore({data: data});
/*set up layout*/
var layout = [[
{'name': 'Description', 'field': 'id', 'width': '100px'}
]];
/*create a new grid*/
var grid = new DataGrid({
id: 'grid',
store: store,
structure: layout,
rowSelector: '20px'
}, "grid");
/*Call startup() to render the grid*/
grid.startup();
});
</script>
However, when I go to my webpage, I get this error:
Uncaught SyntaxError: Unexpected identifier
What am I doing wrong and how do I fix it? Thanks!
You need to add quotes around the values in the dictionary
data.items.push({ id: '{{ item.url }}_{{ item.id }}', col1: '{{ item.description }}' });

Display progress bar while an image gallery is loading on django template

I want to display a progress bar (or loading icon) while a image gallery is loading on django template.
Image gallery is having a div in the template and for that div only the progress bar should appear.
Please refer to http://www.openstudio.fr/jquery/ as I am using this gallery
Your best bet is probably to do this through JavaScript instead of trying to do much of anything in Django. You would have Django populate your JavaScript, and then have the JavaScript do your progress bar. I'll use jQuery UI for the progressbar.
Django Template:
var portfolio = {
image_count = {{ images|length }},
images = [
{% for image in images %}{
'src': "{{ image.url }}",
'title': "{{ image.title }}"
}{% if not forloop.last %},{% endif %}{% endfor %}
]
};
JavaScript:
<script>
// This helps us keep track of the progress:
var count = 0;
var updateProgress = function() {
count++;
// Calculate the % we are through the images.
progress = parseInt((count / portfolio.image_count) * 100);
// Update the progressbar.
$("#progressbar").progressbar("value", progress);
// Check if we're done.
if (progress >= 100) {
$("#progressbar").hide();
// Fire up the multimedia portfolio, per the OP.
$('#multimedia-portfolio').multimedia_portfolio({width: 800});
$("#portfolio-cont").show();
}
}
$(function() {
// Initialize the progressbar at 0%.
$("#progressbar").progressbar({value:0});
// Hide the portfolio for now.
$('#portfolio-cont').hide();
if (portfolio) {
// Loop over the images.
for (var i=0; i<portfolio.image_count; i++) {
var image = portfolio.images[i];
// Create an image, a link, an li.
// Once the image is loaded, will call updateProgress.
var img = $('<img>').attr('src', image.src)
.attr('title', image.title)
.load(updateProgress);
var a = $("<a>").attr("href", image.src)
.addClass("thickbox");
$(a).append(img);
var li = $("<li>").append(a);
// Append the li to the ul.
$('#multimedia-portfolio').append(li);
}
}
});
</script>
This is also assuming that you have this(-ish) HTML:
<div id="progressbar"></div>
<div id="portfolio-cont"><ul id="multimedia-portfolio"></ul></div>
Hope that helps you at least get some direction.