5

I building a website using the (excellent) Flask framework in which I now want to display some numbers. The round filter provided by jinja2 works fine, except for when there is no decimal value:

{{ 1.55555|round(2) }} -> 1.56
{{ 1.5|round(2) }} -> 1.5
{{ 1.0|round(2) }} -> 1.0
{{ 1|round(2) }} -> 1.0

But I want the last two to be displayed like 1 (without a trailing .0). Does anybody know how I can do this with jinja2? All tips are welcome!

[EDIT]

I tried using trim(), but to my surprise the snippet below gives a TypeError: do_trim() takes exactly 1 argument (2 given):

{{ 1.0|round(2)|trim('.0') }}
kramer65
  • 50,427
  • 120
  • 308
  • 488
  • 1
    I don't think you can with default Jinja2 filters. Do it in Python with [Formatting floats in Python without superfluous zeros](http://stackoverflow.com/q/2440692) perhaps, or create your own filter that implements that. – Martijn Pieters Feb 11 '15 at 15:54
  • `trim` expects only the value to trim as argument. You cannot specify WHAT to trim out. – Ricardo Cárdenes Feb 11 '15 at 15:56
  • Warning! "|trim('.0')" turns 10.0 into 1. – Max Jun 22 '20 at 14:08

4 Answers4

7

You can use string filter, then use str.rstrip:

>>> import jinja2
>>> print(jinja2.Template('''
... {{ (1.55555|round(2)|string).rstrip('.0') }}
... {{ (1.5|round(2)|string).rstrip('.0') }}
... {{ (1.0|round(2)|string).rstrip('.0') }}
... {{ (1|round(2)|string).rstrip('.0') }}
... ''').render())

1.56
1.5
1
1

NOTE

Using str.rstrip, you will get an empty string for 0.

>>> jinja2.Template('''{{ (0|round(2)|string()).strip('.0') }}''').render()
u''

Here's a solution to avoid above (call rstrip twice; once with 0, once with .)

>>> print(jinja2.Template('''
... {{ (1.55555|round(2)|string).rstrip('0').rstrip('.') }}
... {{ (1.5|round(2)|string).rstrip('0').rstrip('.') }}
... {{ (1.0|round(2)|string).rstrip('0').rstrip('.') }}
... {{ (1|round(2)|string).rstrip('0').rstrip('.') }}
... {{ (0|round(2)|string).rstrip('0').rstrip('.') }}
... ''').render())

1.56
1.5
1
1
0

UPDATE Above codes will trim 10 to 1. Following code does not have the issue. using format filter.

>>> print(jinja2.Template('''
... {{ ("%.2f"|format(1.55555)).rstrip('0').rstrip('.') }}
... {{ ("%.2f"|format(1.5)).rstrip('0').rstrip('.') }}
... {{ ("%.2f"|format(1.5)).rstrip('0').rstrip('.') }}
... {{ ("%.2f"|format(1.0)).rstrip('0').rstrip('.') }}
... {{ ("%.2f"|format(0)).rstrip('0').rstrip('.') }}
... {{ ("%.2f"|format(10)).rstrip('0').rstrip('.') }}
... ''').render())

1.56
1.5
1.5
1
0
10
falsetru
  • 357,413
  • 63
  • 732
  • 636
5

If you're going to use this a lot, I think it's best to write a custom filter to avoid clutter, like this:

from jinja2 import filters

def myround(*args, **kw):
    # Use the original round filter, to deal with the extra arguments
    res = filters.do_round(*args, **kw)
    # Test if the result is equivalent to an integer and
    # return depending on it
    ires = int(res)
    return (res if res != ires else ires)

Register it, and you're done. Example in the interactive interpreter:

>>> from jinja2 import Environment
>>> env = Environment()
>>> env.filters['myround'] = myround
>>> env.from_string("{{ 1.4|myround(2) }}").render()
u'1.4'
>>> env.from_string("{{ 1.4|myround }}").render()
u'1'
>>> env.from_string("{{ 0.3|myround }}").render()
u'0'
Ricardo Cárdenes
  • 9,004
  • 1
  • 21
  • 34
2

A better solution, to avoid 60.0 becoming 6 and 0.0 becoming empty,

instead of:

(( YOURNUMBER )|string).rstrip('0')

do this:

(( YOURNUMBER )|string )[:-2]

This will cut off the last 2 characters of the string. Since round(0) always produces a number that will have a .0 at the end, this will solve the problem nicely.

cake
  • 658
  • 5
  • 13
0

You can always do

{{ ((1|round(2))|string).split('.')[0] }}

Process breakdown:

  1. 1|round(2) -> 1.0
  2. |string will convert the output to string so that we can use split()
  3. .split('.') will split the string with . delimiter -> ["1", "0"]
  4. As .split() returns an array, [0] after it will get the string at 0th postition -> "1"
  5. [optional] If you want data type of result to be number then do |int at the end