在Django模板中格式化数字


154

我正在尝试格式化数字。例子:

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

它很常见,但是我无法弄清楚应该使用哪个过滤器。

编辑:如果您有通用的Python方法可以执行此操作,则很高兴在模型中添加格式化的字段。


3
如果您的目标用户也在欧洲,请当心。某些欧洲国家(例如德国)使用,作为小数点。
tobltobs

Answers:


312

Django的贡献人性化应用程序执行以下操作:

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

确保将文件添加'django.contrib.humanize'INSTALLED_APPS列表中settings.py


17
为什么这几个简单的过滤器不属于内置过滤器的原因?
PawelRoman

8
@PawelRoman为避免加载一堆很少使用的过滤器和标签(从而使模板渲染更快)
Maxime Lorant 2014年

我在INSTALLED_APPS中添加了“ django.contrib.humanize”,并且在模板中也包含了{%load humanize%},然后重新启动了服务器。但是,当我尝试使用“ intcomma”过滤器时,出现此错误-无效的过滤器:'intcomma'调试跟踪显示settings.py中包含的'django.contrib.humanize'。可能是什么问题?
Manish

1
在这里得到了我自己的问题的答案-我在基本模板中包含了{%load humanize%}(因为很多模板都需要它)。似乎不起作用-当我在相关模板中添加它时,它工作正常!:-)
Manish

如果它不起作用,则可能是由于本地化。在这种情况下,请尝试{{my_num | intcomma:False}}
Jose Cherian


59

关于Ned Batchelder的解决方案,此处为2个小数点和一个美元符号。这就像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)

那么你就可以

{% load my_filters %}
{{my_dollars | currency}}

3
有关上述代码的错误,请尝试以下操作:>>> currency(0.99958) u'$0.00'
Ahsan

1
此代码应放在[your_project] / [your_app] / templatetags / [filtername] .py自己的文件中。然后应使用{%load [filtername]%}将其加载到模板中。有关更多有用和特定的信息,请参阅docs.djangoproject.com/en/1.10/howto/custom-template-tags
强大的

20

尝试在settings.py中添加以下行:

USE_THOUSAND_SEPARATOR = True

这应该工作。

请参阅文档


更新于2018-04-16:

还有一种执行此操作的python方法:

>>> '{:,}'.format(1000000)
'1,000,000'

10
使用时要小心。还将格式化网址中的数字以及您添加到模板中的其他数字
Christoffer

4
我不能对@Christoffer的注释过分强调-在呈现ID并在链接中使用ID的模板中,这可能会引起严重的麻烦!
LaundroMat

这是不恰当的Django模板

@Ben不合适吗?设置中的“ python方式”还是千位分隔符标志?千位分隔符标记对于Django模板应该很好用。您的Django版本是什么?
carton.swing

1
字符串格式(python),因为您不能直接在模板中使用它-您必须将其放在模板标签中(这是一个很好的答案),但是将其扔掉并不能完全解决问题。

11

如果您不想参与语言环境,则可以使用以下函数来格式化数字:

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)

从此函数创建自定义模板过滤器很简单。


10

人文化的解决方案是好的,如果你的网站是英文的。对于其他语言,您需要另一种解决方案:我建议使用Babel。一种解决方案是创建一个自定义模板标签以正确显示数字。方法如下:只需在中创建以下文件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)

然后,您可以像下面这样在模板中使用此模板标记:

{% load sexy_number from sexify %}

{% sexy_number 1234.56 %}
  • 对于美国用户(语言环境为en_US),显示为1,234.56。
  • 对于法语用户(语言环境fr_FR),这将显示1 234,56。
  • ...

当然,您可以改用变量:

{% sexy_number some_variable %}

注意:context参数当前未在我的示例中使用,但我将其放在此处表明您可以轻松地调整此模板标签以使其使用模板上下文中的任何内容。


1
我的语言环境是“ pt_BR”,即使在巴西以“。”分隔,“ intcomma”仍然有效。而不是','为floatvalue = 25000.35 {{floatvalue | intcomma}}的结果为25000.35
Zokis 2013年

没错,但是这种格式不适用于千位分隔符(en_US为25,000.35,fr_FR为25 000,35)。
MiniQuark 2013年

4

人文化的应用程序提供了一个很好和格式化号码的快捷方式,但如果你需要使用一个分离器不同于逗号,它的简单,只是重复使用从人文化的应用程序的代码,则更换分隔字符,并创建一个自定义过滤器。例如,使用空格作为分隔符:

@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)

谢谢。我需要一个点号版本,您的建议救了我!干杯!
kstratis 2014年

3

稍微偏离主题:

我在寻找一种将数字格式化为货币的方法时发现了这个问题,如下所示:

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

我最终做了:

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

您也可以这样做,例如{{ var|stringformat:"1.2f"|cut:"-" }}显示为$50.00(如果要的话, 2位小数。

也许稍微有点怪癖,但也许其他人会发现它很有用。


2

好吧,我找不到Django方式,但确实从模型内部找到了python方式:

def format_price(self):
    import locale
    locale.setlocale(locale.LC_ALL, '')
    return locale.format('%d', self.price, True)

嗯-这是-1',没有任何解释-无济于事。对于那些认为答案在某种程度上不正确的人,请为答覆者和读者的利益说出原因。我想我不喜欢在此功能中设置语言环境(在全球范围内使用)(获取货币的不利影响)-这可以解释-1。
Danny Staple 2012年

我做了第二个-1-如前所述。评论,这s really not correct not giving any reason. Here it很容易:Django有特定的模板(类似于Jinja2-或它的Jinja2),该模板不允许使用标准的python函数。所以这个答案根本没有用。更重要的是,Django有自己的功能来管理它,并编写任何有效的新方法确实不是一个好主意……
tomis

2
我不同意下降投票者的意见-确保该值在到达模板之前在视图函数中正确格式化似乎是一种完全有效的方法。
Paul Tomblin,2013年

1

请注意,更改区域设置是在整个进程范围内进行的,并且不是线程安全的(现在,可能会有副作用,或者可能影响在同一进程中执行的其他代码)。

我的主张:检查Babel软件包。提供了一些与Django模板集成的方法。



1

基于muhuk的答案,我做了这个简单的标记封装python string.format方法。

  • 创建一个 templatetags在您的应用程序文件夹中。
  • format.py在其上创建一个文件。
  • 添加到它:

    from django import template
    
    register = template.Library()
    
    @register.filter(name='format')
    def format(value, fmt):
        return fmt.format(value)
  • 将其加载到模板中 {% load format %}
  • 用它。 {{ some_value|format:"{:0.2f}" }}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.