Django timeseries format and highcharts - django

I'm trying to implement a timeseries in highcharts using Django 2.x
{% for date in timeseries.all %}
{{ date }}
{% if not forloop.last %},
{% endif %}
{% endfor %}
This gives the following as output:
{'flotation_date': datetime.datetime(2002, 2, 2, 0, 0, tzinfo=<UTC>)} ,
{'flotation_date': datetime.datetime(2002, 2, 1, 0, 0, tzinfo=<UTC>)} ,
{'flotation_date': datetime.datetime(2002, 2, 3, 0, 0, tzinfo=<UTC>)} ,
{'flotation_date': datetime.datetime(2002, 2, 4, 0, 0, tzinfo=<UTC>)}
Highcharts is expecting:
1167609600000,
0.7537
],
[
1167696000000,
0.7537
],
[
1167782400000,
0.7559
],
[
1167868800000,
0.7631
],
So the obvious question, how to transform the dictionary into the expected array?
n.b. at this point the time has been omitted, it will be added later.
In my views the data is returned like so, I anticipate this is where the formatting will take place.
timeseries = Flotation.objects.values('flotation_date')

I found a simple way to do this. If your date is a datetime object, do the following.
yourdate.replace(tzinfo=timezone.utc).timestamp() * 1000
This will give you the timestamp. Please note I am creating chart objects in my django views not in templates. But you can write a tag to use in your templates to return the date in EPOCH seconds.

Related

How to iterate pages for pagination if its more than certain number in Flask without SQLAlchemy?

I want to create pagination for my blog using Peewee instead of SQLAlchemy as I seen every tutorial on it, so I'm trying to use something different. I rarely see any tutorial on it. I updated a previous question but there were no responses so I decided to create a new post. Now I already manage to display the pages using range:
{% for page_num in range(1, pagination.get_page_count() + 1) %}
{% if pagination.get_page() == page_num %}
{{ page_num }}
{% else %}
{{ page_num }}
{% endif %}
{% endfor %}
What I'm trying to do now is splitting the pages similar to SQLAlchemy "iter_pages" threshold:
Is there a way I could do this using range, or do I need to use something else?
You can fiddle around with something like this:
def get_page_range(page, total, show=5):
start = max((page - (show // 2)), 1)
stop = min(start + show, total) + 1
start = max(min(start, stop - show), 1)
return list(range(start, stop)[:show])
Example output for pages 1-10 where there are 10 total pages of results, and 5 buttons should be shown:
for i in range(1, 11):
print(i, get_page_range(i, 10, 5))
Output:
1 [1, 2, 3, 4, 5]
2 [1, 2, 3, 4, 5]
3 [1, 2, 3, 4, 5]
4 [2, 3, 4, 5, 6]
5 [3, 4, 5, 6, 7]
6 [4, 5, 6, 7, 8]
7 [5, 6, 7, 8, 9]
8 [6, 7, 8, 9, 10]
9 [6, 7, 8, 9, 10]
10 [6, 7, 8, 9, 10]

Weird behavior in Django queryset union of values

I want to join the sum of related values from users with the users that do not have those values.
Here's a simplified version of my model structure:
class Answer(models.Model):
person = models.ForeignKey(Person)
points = models.PositiveIntegerField(default=100)
correct = models.BooleanField(default=False)
class Person(models.Model):
# irrelevant model fields
Sample dataset:
Person | Answer.Points
------ | ------
3 | 50
3 | 100
2 | 100
2 | 90
Person 4 has no answers and therefore, points
With the query below, I can achieve the sum of points for each person:
people_with_points = Person.objects.\
filter(answer__correct=True).\
annotate(points=Sum('answer__points')).\
values('pk', 'points')
<QuerySet [{'pk': 2, 'points': 190}, {'pk': 3, 'points': 150}]>
But, since some people might not have any related Answer entries, they will have 0 points and with the query below I use Coalesce to "fake" their points, like so:
people_without_points = Person.objects.\
exclude(pk__in=people_with_points.values_list('pk')).\
annotate(points=Coalesce(Sum('answer__points'), 0)).\
values('pk', 'points')
<QuerySet [{'pk': 4, 'points': 0}]>
Both of these work as intended but I want to have them in the same queryset so I use the union operator | to join them:
everyone = people_with_points | people_without_points
Now, for the problem:
After this, the people without points have their points value turned into None instead of 0.
<QuerySet [{'pk': 2, 'points': 190}, {'pk': 3, 'points': 150}, {'pk': 4, 'points': None}]>
Anyone has any idea of why this happens?
Thanks!
I should mention that I can fix that by annotating the queryset again and coalescing the null values to 0, like this:
everyone.\
annotate(real_points=Concat(Coalesce(F('points'), 0), Value(''))).\
values('pk', 'real_points')
<QuerySet [{'pk': 2, 'real_points': 190}, {'pk': 3, 'real_points': 150}, {'pk': 4, 'real_points': 0}]>
But I wish to understand why the union does not work as I expected in my original question.
EDIT:
I think I got it. A friend instructed me to use django-debug-toolbar to check my SQL queries to investigate further on this situation and I found out the following:
Since it's a union of two queries, the second query annotation is somehow not considered and the COALESCE to 0 is not used. By moving that to the first query it is propagated to the second query and I could achieve the expected result.
Basically, I changed the following:
# Moved the "Coalesce" to the initial query
people_with_points = Person.objects.\
filter(answer__correct=True).\
annotate(points=Coalesce(Sum('answer__points'), 0)).\
values('pk', 'points')
# Second query does not have it anymore
people_without_points = Person.objects.\
exclude(pk__in=people_with_points.values_list('pk')).\
values('pk', 'points')
# We will have the values with 0 here!
everyone = people_with_points | people_without_points

Jinja Map/Format Decimal Values

I'm having trouble formatting a list of values in Jinja.
Current List:
[0, 0.2608695652173913, 0]
Needed List:
[0, 26.08, 0]
Code:
[{{ record['result']|map(attribute='record')|join(', ') }}]
What is the correct syntax to apply the format filter with something like {0:0.2f}?
You can do something like this...
def FormatDecimal(value):
return "{0:0.2f}".format(float(value))
jinja2.filters.FILTERS['FormatDecimal'] = FormatDecimal
Then use this in your template...
{{ SomeValue | FormatDecimal }}
Hope this helps!

Django Template Save operation result into a variable

I have a listing counter "2370" and the page only shows "12" item so I want to calculate the pages number, I did the solution below
{% widthratio listing.total_count 12 1 %}
so, how I can save the result into a variable?
{% set total_pages = widthratio listing.total_count 12 1 %}
this one didn't work
If would choose Rohans comment, but if you would write your own templatetags, use an assignment_tag (https://docs.djangoproject.com/en/1.7/howto/custom-template-tags/#assignment-tags, exists since Django 1.4).
#register.assignment_tag
def page_numbers(total_items, items_per_page):
if not total_items:
return 0
# int divisions round down (1 / 12 = 0), so just add 1 to cover this
return total_items / items_per_page + 1
Within the template you should use;
{% page_numbers listing.total_count 12 as page_nrs %}

Split before decimal in django

i have a variable which fetches the data from database
{{i.rewardpoints}}
and the values it returns such as 1.799 or 12 the db has multiple values which contains decimals and without decimals
but i need to show the values without decimals
how can i do this
To round to nearest integer:
{{ i.rewardpoints|floatformat:"0" }}
To get the integer part:
{{ i.rewardpoints|stringformat:"d" }}
The floatformat filter documentation
The stringformat filter documentation
In [19]: tpl = Template('{{ x|stringformat:"d" }} {{ x|floatformat:"0" }}')
In [20]: tpl.render(Context({'x': 1.1}))
Out[20]: u'1 1'
In [21]: tpl.render(Context({'x': 1.9}))
Out[21]: u'1 2'