1

I am trying to create a rating (stars) ui within my app. All of my 'ratings' come in as float. I want to round that rating to make it an integer and display that many stars. I can't seem to figure out how to get jinja to like it.

Example Ratings: 3.0, 2.3, 5.0, 4.6, etc...

Fails because with TypeError: 'float' object cannot be interpreted as an integer

{% if book.average_score %}
  {% for s in range(book.average_score) %}
     <i class="fas fa-star"></i>
  {% endfor %}
{% endif %}

I thought I could just use math:

{% if book.average_score %}
  {% for s in range(math.ceil(book.average_score)) %}
     <i class="fas fa-star"></i>
  {% endfor %}
{% endif %}

But, this results in jinja2.exceptions.UndefinedError: 'math' is undefined. I'm assuming this is because I'm using Flask and the template has no idea about the math library.

I then was playing around with round:

{% if book.average_score %}
  {% for s in range(round(book.average_score)) %}
     <i class="fas fa-star"></i>
  {% endfor %}
{% endif %}

But then I end up with jinja2.exceptions.UndefinedError: 'round' is undefined

I did some more variations of using round following the round documentation but no success. I know in Angular, you have pipes that really help with these sort of things. Does jinja have something similar or am I just way off the mark here?

This SOF thread seems to be the closest thing I can find to the problem I'm trying to solve. Doesn't seem to get me too much further, however.

larsks
  • 277,717
  • 41
  • 399
  • 399
mwilson
  • 12,295
  • 7
  • 55
  • 95

1 Answers1

8

You're using Jinja, but you've linked to Python function documentation. Jinja != Python: you need to use filters or object methods when working with Jinja expressions. So, for example, you could use the int filter:

{% if book.average_score %}
  {% for s in range(book.average_score|int) %}
     <i class="fas fa-star"></i>
  {% endfor %}
{% endif %}

Or the round filter:

{% if book.average_score %}
  {% for s in range(book.average_score|round) %}
     <i class="fas fa-star"></i>
  {% endfor %}
{% endif %}

You can control the behavior of the round filter with the method parameter, which can be either common (the default), floor, or ceil:

{% if book.average_score %}
  {% for s in range(book.average_score|round(method='ceil')) %}
     <i class="fas fa-star"></i>
  {% endfor %}
{% endif %}

Update

It looks like since this was written that the round filter may have changed. Looking at the documentation, the mode parameter doesn't exist, but there is a method parameter. The following work:

  • Specify a precision and a method; no keyword args required:

    >>> t = jinja2.Template("Value: {{ value|round(2, 'ceil') }}")
    >>> print(t.render(value=4.1234))
    Value: 4.13
    
  • Specify just a rounding method; use the method keyword:

    >>> t = jinja2.Template("Value: {{ value|round(method='ceil') }}")
    >>> print(t.render(value=4.1234))
    Value: 5.0
    

I've updated the original part of the answer to reflect this change.

larsks
  • 277,717
  • 41
  • 399
  • 399
  • 3
    so this didn't work for decimal type.. had to use this - https://stackoverflow.com/a/48727177/2048229 – Mitalee Rao May 20 '20 at 03:22
  • 1
    `...|int)` worked just ok for me for decimal type (float type from sqlite table), as a result I got int in rendered template by jinja – IAmBotmaker Mar 11 '21 at 11:55
  • TypeError: do_round() got an unexpected keyword argument 'mode' – Harsha Biyani Oct 25 '21 at 11:07
  • 1
    @HarshaBiyani thanks, it looks as if the syntax may have changed. I've updated the answer to include examples that work with the current release. – larsks Oct 25 '21 at 12:48