Sformatuj liczby w szablonach django

153

Próbuję sformatować liczby. Przykłady:

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

Wydaje się, że jest to dość powszechna czynność, ale nie mogę dowiedzieć się, którego filtra mam użyć.

Edycja: jeśli masz na to ogólny sposób w Pythonie, z przyjemnością dodam sformatowane pole do mojego modelu.

Oli
źródło
3
Uważaj, jeśli docelowi użytkownicy są również w Europie. Niektóre kraje europejskie, takie jak Niemcy, używają znaku dziesiętnego.
tobltobs

Odpowiedzi:

312

Aplikacja humanizująca dostarczona przez Django robi to:

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

Pamiętaj, aby dodać 'django.contrib.humanize'do swojej INSTALLED_APPSlisty w settings.pypliku.

Ned Batchelder
źródło
17
Czy istnieje powód, dla którego tych kilka prostych filtrów nie jest częścią filtrów wbudowanych?
PawelRoman
8
@PawelRoman Aby uniknąć ładowania wielu rzadko używanych filtrów i tagów (a tym samym przyspieszyć renderowanie szablonu)
Maxime Lorant
Dodałem „django.contrib.humanize” do INSTALLED_APPS, a także włączyłem {% load humanize%} do mojego szablonu i zrestartowałem serwer. Jednak gdy próbuję użyć filtru „intcomma”, pojawia się ten błąd - Nieprawidłowy filtr: „intcomma”. Śledzenie debugowania pokazuje „django.contrib.humanize” zawarte w settings.py. Jaki może być możliwy problem?
Manish
1
Mam tutaj odpowiedź na mój własny problem - umieściłem {% load humanize%} w podstawowym szablonie (ponieważ potrzebuję go do wielu szablonów). Wygląda na to, że nie działa - kiedy dodałem go w odpowiednich szablonach, działało dobrze! :-)
Manish
Jeśli to nie zadziała, może to być spowodowane lokalizacją. Wypróbuj {{my_num | intcomma: False}} w takim przypadku
Jose Cherian
105

Opierając się na innych odpowiedziach, aby rozszerzyć to na elementy pływające, możesz:

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

Dokumentacja: floatformat, intcomma.

Vinod Kurup
źródło
59

Jeśli chodzi o rozwiązanie Neda Batcheldera, tutaj jest ono z dwoma miejscami po przecinku i znakiem dolara. To idzie gdzieś jakmy_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)

Wtedy możesz

{% load my_filters %}
{{my_dollars | currency}}
Dave Aaron Smith
źródło
3
Błąd w powyższym kodzie, spróbuj tego:>>> currency(0.99958) u'$0.00'
Ahsan
1
Ten kod powinien znajdować się w swoim własnym pliku w [twój_projekt] / [twoja_aplikacja] / templatetags / [nazwa_pliku] .py. Następnie powinien zostać załadowany do szablonu z {% load [nazwa_pliku]%}. Więcej przydatnych i szczegółowych informacji można znaleźć na stronie docs.djangoproject.com/en/1.10/howto/custom-template-tags .
mightypile
20

Spróbuj dodać następujący wiersz w settings.py:

USE_THOUSAND_SEPARATOR = True

To powinno działać.

Zapoznaj się z dokumentacją .


aktualizacja 16.04.2018:

Jest też sposób na zrobienie tego w Pythonie:

>>> '{:,}'.format(1000000)
'1,000,000'
karton. huśtawka
źródło
10
Zachowaj ostrożność podczas korzystania z tego. Sformatuje również liczby w adresach URL i inne, które dodasz do szablonu
Christoffer
4
Nie mogę wystarczająco podkreślić komentarza @Christoffer - w szablonach, w których identyfikatory są renderowane i używane w linkach, może to powodować poważne bóle głowy!
LaundroMat
To nie jest odpowiednie dla szablonów Django
Ben,
@Ben, które nie jest właściwe? „sposób Pythona” czy flaga separatora tysięcy w ustawieniach? flaga separatora tysięcy powinna działać dobrze dla szablonów Django. Jaka jest twoja wersja Django?
karton. Huśtawka
1
Format ciągu (python) sposób, ponieważ nie można go używać bezpośrednio w szablonach - musiałbyś umieścić to w tagu szablonu (co jest dobrą odpowiedzią), ale samo wyrzucenie tego jest mało przydatne jako pełna odpowiedź.
Ben
11

Jeśli nie chcesz angażować się w ustawienia regionalne, oto funkcja formatująca liczby:

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)

Utworzenie niestandardowego filtru szablonu na podstawie tej funkcji jest banalne.

muhuk
źródło
10

Rozwiązanie humanizacji jest w porządku, jeśli Twoja witryna jest w języku angielskim. W przypadku innych języków potrzebujesz innego rozwiązania: polecam używanie Babel . Jednym z rozwiązań jest utworzenie niestandardowego tagu szablonu, aby poprawnie wyświetlać liczby. Oto jak: po prostu utwórz następujący plik w 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)

Następnie możesz użyć tego tagu szablonu w swoich szablonach w następujący sposób:

{% load sexy_number from sexify %}

{% sexy_number 1234.56 %}
  • Dla użytkownika amerykańskiego (locale en_US) to wyświetla 1,234,56.
  • Dla francuskiego użytkownika (ustawienie regionalne fr_FR) wyświetla 1 234,56.
  • ...

Oczywiście możesz zamiast tego użyć zmiennych:

{% sexy_number some_variable %}

Uwaga:context parametr nie jest obecnie stosowany w moim przykładzie, ale umieścić go tam, aby pokazać, że można łatwo dostosować ten szablon tag, aby go używać niczego, co w kontekście szablonu.

MiniQuark
źródło
1
moje ustawienie regionalne to „pt_BR”, a „intcomma” działa nawet w Brazylii, ponieważ jest oddzielony znakiem „”. a nie przez „,” będąc floatvalue = 25000.35 {{floatvalue | intcomma}} daje 25000.35
Zokis
Masz rację, ale ten format nie jest odpowiedni w odniesieniu do separatora tysięcy (25 000,35 dla en_US i 25 000,35 dla fr_FR).
MiniQuark
4

Aplikacja humanizująca oferuje przyjemny i szybki sposób formatowania liczby, ale jeśli potrzebujesz użyć separatora innego niż przecinek, możesz po prostu ponownie użyć kodu z aplikacji humanizującej , zastąpić znak separatora i utworzyć niestandardowy filtr . Na przykład użyj spacji jako separatora:

@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
źródło
Dzięki. Potrzebowałem wersji kropkowej, a Twoja sugestia mnie uratowała! Twoje zdrowie!
kstratis
3

Nieco poza tematem:

Znalazłem to pytanie, szukając sposobu na sformatowanie liczby jako waluty, na przykład:

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

Skończyło się na zrobieniu:

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

Możesz także zrobić, np. {{ var|stringformat:"1.2f"|cut:"-" }}Wyświetlić jako $50.00(z 2 miejscami po przecinku, jeśli tego chcesz.

Może trochę po stronie zhackowanej, ale może ktoś inny uzna to za przydatne.

Felix Böhme
źródło
2

Cóż, nie mogłem znaleźć drogi Django, ale znalazłem sposób w Pythonie z wnętrza mojego modelu:

def format_price(self):
    import locale
    locale.setlocale(locale.LC_ALL, '')
    return locale.format('%d', self.price, True)
Oli
źródło
Hmm - to było -1'd, bez wyjaśnienia - nieprzydatne. Ci, którzy uważają, że odpowiedź jest w jakiś sposób niepoprawna, powiedz dlaczego, na korzyść osoby odpowiadającej i czytelników. Przypuszczam, że nie jestem fanem ustawiania locale (które ma zasięg globalny), w tej jednej funkcji (nieprzyjemny efekt uboczny zdobycia waluty) - co mogłoby wyjaśniać -1.
Danny Staple
Zrobiłem drugie -1 - jak opisano w poprzednim. komentarz, to s really not correct not giving any reason. Here itproste: Django ma specjalny szablon (podobny do Jinja2 - lub Jinja2), który nie pozwala na standardowe funkcje Pythona. Więc ta odpowiedź nie jest w ogóle przydatna. Co więcej, Django ma własne funkcje, które tym zarządzają, a pisanie czegoś nowego to, co działa, to naprawdę zły pomysł ...
tomis
2
Nie zgadzam się ze zwolennikami - upewnienie się, że wartość jest odpowiednio sformatowana w funkcji widoku, zanim trafi do szablonu, wydaje się całkowicie poprawnym podejściem.
Paul Tomblin
1

Należy pamiętać, że zmiana ustawień regionalnych dotyczy całego procesu i nie jest bezpieczna dla wątków (może mieć skutki uboczne lub może wpływać na inny kod wykonywany w ramach tego samego procesu).

Moja propozycja: sprawdź pakiet Babel . Dostępne są sposoby integracji z szablonami Django.

zgoda
źródło
1

Opierając się na odpowiedzi muhuk, zrobiłem tę prostą string.formatmetodę hermetyzacji znaczników w Pythonie .

  • Utwórz templatetagsw folderze aplikacji.
  • Utwórz format.pyna nim plik.
  • Dodaj do tego:

    from django import template
    
    register = template.Library()
    
    @register.filter(name='format')
    def format(value, fmt):
        return fmt.format(value)
  • Załaduj go do swojego szablonu {% load format %}
  • Użyj tego. {{ some_value|format:"{:0.2f}" }}
gekony
źródło