Format numbers in django templates
Question:
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.
Answers:
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)
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.
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.
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.
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}}
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)
Building on other answers, to extend this to floats, you can do:
{% load humanize %}
{{ floatvalue|floatformat:2|intcomma }}
Documentation: floatformat
, intcomma
.
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.
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.
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'
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)
.
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}" }}
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.
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.
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)
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.
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.
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.
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}}
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)
Building on other answers, to extend this to floats, you can do:
{% load humanize %}
{{ floatvalue|floatformat:2|intcomma }}
Documentation: floatformat
, intcomma
.
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.
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.
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'
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)
.
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}" }}
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.