Формат чисел в шаблонах Django

153

Я пытаюсь отформатировать числа. Примеры:

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

Это довольно распространенная вещь, но я не могу понять, какой фильтр я должен использовать.

Изменить: Если у вас есть общий способ Python сделать это, я рад добавить отформатированное поле в моей модели.

Oli
источник
3
Будьте осторожны, если ваши целевые пользователи также находятся в Европе. Некоторые европейские страны, такие как Германия, используют в качестве десятичного знака.
tobltobs

Ответы:

313

Предложенное Django гуманизированное приложение делает это:

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

Не забудьте добавить 'django.contrib.humanize'в свой INSTALLED_APPSсписок в settings.pyфайле.

Нед Бэтчелдер
источник
17
Есть ли причина, по которой эти несколько простых фильтров не входят в состав встроенных фильтров?
PawelRoman
8
@PawelRoman Чтобы избежать загрузки множества редко используемых фильтров и тегов (и, следовательно, ускорить рендеринг шаблонов)
Maxime Lorant
Я добавил django.contrib.humanize в INSTALLED_APPS, а также включил {% load humanize%} в свой шаблон и перезапустил сервер. Однако, когда я пытаюсь использовать фильтр «intcomma», я получаю эту ошибку - Неверный фильтр: «intcomma» Трассировка отладки показывает «django.contrib.humanize», включенный в settings.py. В чем может быть возможная проблема?
Маниш
1
Получил ответ на мою собственную проблему здесь - я включил {% load humanize%} в базовый шаблон (так как он мне нужен для большого количества шаблонов). Кажется, это не работает - когда я добавил его в соответствующие шаблоны, он работал нормально! :-)
Маниш
Если это не работает, это может быть связано с локализацией. Попробуйте {{my_num | intcomma: False}} в этом случае
Хосе Шериан
105

Основываясь на других ответах, чтобы распространить это на поплавки, вы можете сделать:

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

Документация: floatformat, intcomma.

Винод Куруп
источник
59

Что касается решения Неда Батчелдера, то здесь оно с двумя десятичными знаками и знаком доллара. Это идет где-то как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'
carton.swing
источник
10
Будьте осторожны при использовании этого. Также будет форматировать числа в URL и другие, которые вы добавляете в шаблон
Christoffer
4
Я не могу не подчеркнуть комментарий @Christoffer - в шаблонах, где идентификаторы отображаются и используются в ссылках, это может вызвать серьезные головные боли!
LaundroMat
Это не подходит для шаблонов Django
Бен
@ Бен, который не подходит? "путь питона" или флаг разделителя тысяч в настройках? Флаг разделения тысяч должен хорошо работать для шаблонов 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)

Создание пользовательского шаблона шаблона из этой функции тривиально.

muhuk
источник
10

Humanize решение хорошо , если ваш веб - сайт на английском языке. Для других языков вам нужно другое решение: я рекомендую использовать 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 %}
  • Для американского пользователя (locale en_US) это отображает 1 234,56.
  • Для французского пользователя (locale fr_FR) это отображает 1 234,56.
  • ...

Конечно, вы можете использовать переменные вместо:

{% sexy_number some_variable %}

Примечание:context параметр в настоящее время не используется в моем примере, но я положил его туда , чтобы показать , что вы можете легко настроить этот шаблон тег , чтобы сделать его использовать что - нибудь , что в контексте шаблона.

MiniQuark
источник
1
моя локаль - «pt_BR», а «intcomma» работает даже в Бразилии, где разделение - «.» а не ',' будучи floatvalue = 25000.35 {{floatvalue | intcomma}} приводит к 25000.35
Zokis
Вы правы, но этот формат не подходит для разделителя тысяч (25 000,35 для en_US и 25 000,35 для fr_FR).
MiniQuark
4

Приложение Humanize предлагает удобный и быстрый способ форматирования числа, но если вам нужно использовать разделитель, отличный от запятой, просто повторно использовать код из приложения Humanize , заменить символ разделителя и создать собственный фильтр . Например, используйте пробел в качестве разделителя:

@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
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)
Oli
источник
Хм - это было -1, без объяснения причин - бесполезно. Для тех, кто думает, что ответ каким-то образом неверен, пожалуйста, скажите, почему в интересах ответчика и читателей. Я полагаю, что я не являюсь поклонником установки языка (который является глобальным в пределах досягаемости), в этой единственной функции (неприятный побочный эффект получения валюты) - который мог бы объяснить -1.
Дэнни Стейпл
Я сделал второй -1 - как описано в пред. комментарий, это s really not correct not giving any reason. Here itпросто: у Django есть специальный шаблон (похожий на Jinja2 - или это Jinja2), который не позволяет использовать стандартные функции Python. Так что этот ответ бесполезен вообще. Более того, у Django есть собственные функции, управляющие этим и пишущие что-то новое, что работает, на самом деле не очень хорошая идея ...
Tomis
2
Я не согласен с downvoters - проверка того, что значение правильно отформатировано в функции представления до того, как оно попадет в шаблон, выглядит как совершенно правильный подход.
Пол Томблин
1

Помните, что изменение языкового стандарта распространяется на весь процесс и не обеспечивает потокобезопасность (а именно, может иметь побочные эффекты или повлиять на другой код, выполняемый в том же процессе).

Мое предложение: проверить пакет Babel . Доступны некоторые способы интеграции с шаблонами Django.

Zgoda
источник
1

Основываясь на ответе Мухука, я сделал этот простой string.formatметод инкапсуляции тегов python .

  • Создайте 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}" }}
гекконы
источник