196

I'm trying to format numbers. Examples:

1     => 1
12    => 12
123   => 123
1234  => 1,234
12345 => 12,345

It strikes as a fairly common thing to do but I can't figure out which filter I'm supposed to use.

Edit: If you've a generic Python way to do this, I'm happy adding a formatted field in my model.

Oli
  • 235,628
  • 64
  • 220
  • 299
  • 4
    Be careful if your target users are also in Europe. Some European countries like Germany use , as decimal mark. – tobltobs Jan 20 '17 at 21:12

13 Answers13

412

Django's contributed humanize application does this:

{% load humanize %}
{{ my_num|intcomma }}

Be sure to add 'django.contrib.humanize' to your INSTALLED_APPS list in the settings.py file.

Maxime Lorant
  • 34,607
  • 19
  • 87
  • 97
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • 22
    Is there a reason why these few simple filters are not part of the built-in filters? – PawelRoman Jul 19 '13 at 09:59
  • 13
    @PawelRoman To avoid the loading of a bunch of filters and tags rarely used (and so make the template rendering faster) – Maxime Lorant May 18 '14 at 12:43
  • I have added 'django.contrib.humanize' in INSTALLED_APPS and also included {% load humanize %} in my template as well and restarted the server. However , when I try to use "intcomma" filter, I get this error - Invalid filter: 'intcomma' The debug trace shows 'django.contrib.humanize' included in settings.py. What could be the possible problem? – Manish Mar 07 '15 at 08:35
  • 1
    Got Answer to my own problem here - I had included {% load humanize %} in the base template (since I need it for lot of templates). It seems it does not work - when I added it in the relevant templates, it worked fine! :-) – Manish Mar 07 '15 at 09:34
  • 1
    If it doesnt work, it might be due to localization. Try {{ my_num|intcomma:False }} in that case – Jose Cherian Jan 24 '20 at 02:00
133

Building on other answers, to extend this to floats, you can do:

{% load humanize %}
{{ floatvalue|floatformat:2|intcomma }}

Documentation: floatformat, intcomma.

Flimm
  • 136,138
  • 45
  • 251
  • 267
Vinod Kurup
  • 2,676
  • 1
  • 23
  • 18
  • 1
    Django 4.0 and greater allows for a `g` arg that turns on grouping. `{{ floatvalue|floatformat:"2g" }}` will give 2 decimal places and group by "thousands" in a localized format. – Tim Tisdall Jan 11 '23 at 13:01
66

Regarding Ned Batchelder's solution, here it is with 2 decimal points and a dollar sign. This goes somewhere like my_app/templatetags/my_filters.py

from django import template
from django.contrib.humanize.templatetags.humanize import intcomma

register = template.Library()

def currency(dollars):
    dollars = round(float(dollars), 2)
    return "$%s%s" % (intcomma(int(dollars)), ("%0.2f" % dollars)[-3:])

register.filter('currency', currency)

Then you can

{% load my_filters %}
{{my_dollars | currency}}
Dave Aaron Smith
  • 4,517
  • 32
  • 37
  • 3
    Bug on above code, try this: `>>> currency(0.99958) u'$0.00'` – Ahsan Apr 05 '12 at 07:39
  • 1
    This code should go in its own file at [your_project]/[your_app]/templatetags/[filtername].py. It should then be loaded in the template with {% load [filtername] %}. See https://docs.djangoproject.com/en/1.10/howto/custom-template-tags/ for more helpful and specific information. – mightypile Mar 05 '17 at 01:50
37

Try adding the following line in settings.py:

USE_THOUSAND_SEPARATOR = True

This should work.

Refer to documentation.


update at 2018-04-16:

There is also a python way to do this thing:

>>> '{:,}'.format(1000000)
'1,000,000'
Saransh Singh
  • 730
  • 4
  • 11
carton.swing
  • 1,517
  • 17
  • 12
  • 22
    Be carefull when using this. Will also format numbers in urls and other that you add to the template – Christoffer Jun 20 '16 at 15:58
  • 6
    I can't stress @Christoffer 's comment enough - in templates where id's are rendered and used in links, this can cause major headaches! – Mathieu Dhondt Sep 11 '18 at 17:50
  • This is not appropriate for Django templates – Ben Apr 21 '19 at 22:17
  • @Ben which is not appropriate? "the python way" or the thousand separator flag in settings? the thousand separator flag should be works well for Django templates.what is your Django's version? – carton.swing Apr 22 '19 at 06:29
  • 1
    The string format (the python) way because you cannot use this directly in templates - you would have to put this in a template tag (which is a fine answer), but just throwing this out is of little use as a complete answer. – Ben Apr 22 '19 at 15:20
  • I used to had a weird problem where if I'd set `floatformat:1` or greater, for example, all the separators were converted into commas. With the `USE_THOUSAND_SEPARATOR` setting they return to normal. – Tito Leiva Feb 14 '20 at 08:31
  • @Christoffer you are right. The thousand separator setting forces every number to be converted to this format and can cause multiple issues, overall if your site is in another locale. – Tito Leiva Feb 14 '20 at 08:57
  • this works very well too. i use it when writing pure python codes and not django – Abayomi Olowu Mar 02 '23 at 13:12
11

If you don't want to get involved with locales here is a function that formats numbers:

def int_format(value, decimal_points=3, seperator=u'.'):
    value = str(value)
    if len(value) <= decimal_points:
        return value
    # say here we have value = '12345' and the default params above
    parts = []
    while value:
        parts.append(value[-decimal_points:])
        value = value[:-decimal_points]
    # now we should have parts = ['345', '12']
    parts.reverse()
    # and the return value should be u'12.345'
    return seperator.join(parts)

Creating a custom template filter from this function is trivial.

muhuk
  • 15,777
  • 9
  • 59
  • 98
10

The humanize solution is fine if your website is in English. For other languages, you need another solution: I recommend using Babel. One solution is to create a custom template tag to display numbers properly. Here's how: just create the following file in your_project/your_app/templatetags/sexify.py:

# -*- coding: utf-8 -*-
from django import template
from django.utils.translation import to_locale, get_language
from babel.numbers import format_number

register = template.Library()

def sexy_number(context, number, locale = None):
    if locale is None:
        locale = to_locale(get_language())
    return format_number(number, locale = locale)

register.simple_tag(takes_context=True)(sexy_number)

Then you can use this template tag in your templates like this:

{% load sexy_number from sexify %}

{% sexy_number 1234.56 %}
  • For an american user (locale en_US) this displays 1,234.56.
  • For a french user (locale fr_FR), this displays 1 234,56.
  • ...

Of course you can use variables instead:

{% sexy_number some_variable %}

Note: the context parameter is currently not used in my example, but I put it there to show that you can easily tweak this template tag to make it use anything that's in the template context.

MiniQuark
  • 46,633
  • 36
  • 147
  • 183
  • 1
    my locale is 'pt_BR' and "intcomma" works even in Brazil being the separation by '.' and not by ',' being floatvalue = 25000.35 {{floatvalue|intcomma}} results in 25000.35 – Zokis Mar 01 '13 at 20:01
  • You're right, but this format is not appropriate regarding the thousands separator (25,000.35 for en_US and 25 000,35 for fr_FR). – MiniQuark Mar 01 '13 at 22:08
5

Based on muhuk answer I did this simple tag encapsulating python string.format method.

  • Create a templatetags at your's application folder.
  • Create a format.py file on it.
  • Add this to it:

    from django import template
    
    register = template.Library()
    
    @register.filter(name='format')
    def format(value, fmt):
        return fmt.format(value)
    
  • Load it in your template {% load format %}
  • Use it. {{ some_value|format:"{:0.2f}" }}
geckos
  • 5,687
  • 1
  • 41
  • 53
4

The humanize app offers a nice and a quick way of formatting a number but if you need to use a separator different from the comma, it's simple to just reuse the code from the humanize app, replace the separator char, and create a custom filter. For example, use space as a separator:

@register.filter('intspace')
def intspace(value):
    """
    Converts an integer to a string containing spaces every three digits.
    For example, 3000 becomes '3 000' and 45000 becomes '45 000'.
    See django.contrib.humanize app
    """
    orig = force_unicode(value)
    new = re.sub("^(-?\d+)(\d{3})", '\g<1> \g<2>', orig)
    if orig == new:
        return new
    else:
        return intspace(new)
Enis Afgan
  • 180
  • 1
  • 5
3

Slightly off topic:

I found this question while looking for a way to format a number as currency, like so:

$100
($50)  # negative numbers without '-' and in parens

I ended up doing:

{% if   var >= 0 %} ${{ var|stringformat:"d" }}
{% elif var <  0 %} $({{ var|stringformat:"d"|cut:"-" }})
{% endif %}

You could also do, e.g. {{ var|stringformat:"1.2f"|cut:"-" }} to display as $50.00 (with 2 decimal places if that's what you want.

Perhaps slightly on the hacky side, but maybe someone else will find it useful.

Felix Böhme
  • 508
  • 5
  • 12
3

Not sure why this has not been mentioned, yet:

{% load l10n %}

{{ value|localize }}

https://docs.djangoproject.com/en/1.11/topics/i18n/formatting/#std:templatefilter-localize

You can also use this in your Django code (outside templates) by calling localize(number).

From @Skratt's comment:

In your settings file, make sure to add:

USE_L10N = True
USE_THOUSAND_SEPARATOR = True
Risadinha
  • 16,058
  • 2
  • 88
  • 91
  • Best answer for me. But don't forget to add in settings.py: `USE_THOUSAND_SEPARATOR = True` in addition to `USE_L10N = True` – Skratt Aug 15 '23 at 14:26
  • 1
    @Skratt - thank you, I've updated my answer to add a note on these settings – Risadinha Aug 16 '23 at 09:47
3

In case someone stumbles upon this, in Django 2.0.2 you can use this

Thousand separator. Be sure to read format localization as well.

chidimo
  • 2,684
  • 3
  • 32
  • 47
2

Well I couldn't find a Django way, but I did find a python way from inside my model:

def format_price(self):
    import locale
    locale.setlocale(locale.LC_ALL, '')
    return locale.format('%d', self.price, True)
Oli
  • 235,628
  • 64
  • 220
  • 299
  • Hmm - this has been -1'd, with no explanation - unhelpful. For those who think the answer is incorrect in some way, please do say why for the benefit of the answerer and readers. I suppose I am not a fan of setting the locale (which is global in reach), in this one function (unpleasant side affect of getting the currency) - which could explain the -1. – Danny Staple Jun 14 '12 at 20:25
  • I did second -1 - as described in prev. comment, it`s really not correct not giving any reason. Here it`s easy: Django has got specific template (similar to Jinja2 - or it`s Jinja2) which does not allowing standard python functions. So this answer is not usefull at all. What is more, Django has got own functions managing this and writting anything new what is working is really not good idea... – tomis May 07 '13 at 22:56
  • 2
    I disagree with the downvoters - making sure the value is properly formatted in the view function before it hits the template seems like a perfectly valid approach. – Paul Tomblin Aug 15 '13 at 19:04
1

Be aware that changing locale is process-wide and not thread safe (iow., can have side effects or can affect other code executed within the same process).

My proposition: check out the Babel package. Some means of integrating with Django templates are available.

zgoda
  • 12,775
  • 4
  • 37
  • 46