mwilson
mwilson

Reputation: 12910

Round a float to an int within jinja2

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.

Upvotes: 2

Views: 8103

Answers (1)

larsks
larsks

Reputation: 311750

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.

Upvotes: 10

Related Questions