Memformat angka dalam template Django

154

Saya mencoba memformat angka. Contoh:

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

Itu dianggap sebagai hal yang cukup umum untuk dilakukan tetapi saya tidak tahu filter mana yang seharusnya saya gunakan.

Sunting: Jika Anda memiliki cara Python umum untuk melakukan ini, saya senang menambahkan bidang yang diformat dalam model saya.

Oli
sumber
3
Hati-hati jika target pengguna Anda juga di Eropa. Beberapa negara Eropa seperti Jerman menggunakan, sebagai tanda desimal.
tobltobs

Jawaban:

312

Aplikasi memanusiakan Django yang berkontribusi melakukan ini:

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

Pastikan untuk menambahkan 'django.contrib.humanize'ke INSTALLED_APPSdaftar Anda di settings.pyfile.

Ned Batchelder
sumber
17
Apakah ada alasan mengapa beberapa filter sederhana ini bukan bagian dari filter bawaan?
PawelRoman
8
@PawelRoman Untuk menghindari pemuatan sekelompok filter dan tag yang jarang digunakan (dan karenanya membuat rendering templat lebih cepat)
Maxime Lorant
Saya telah menambahkan 'django.contrib.humanize' di INSTALLED_APPS dan juga memasukkan {% load memanusiakan%} dalam template saya juga dan memulai kembali server. Namun, ketika saya mencoba menggunakan filter "intcomma", saya mendapatkan kesalahan ini - Filter tidak valid: 'intcomma' Jejak debug menunjukkan 'django.contrib.humanize' termasuk dalam settings.py. Apa yang mungkin menjadi masalah?
Manish
1
Mendapat Jawaban untuk masalah saya sendiri di sini - Saya telah memasukkan {% load humanize%} dalam template dasar (karena saya membutuhkannya untuk banyak template). Tampaknya tidak berfungsi - ketika saya menambahkannya di templat yang relevan, itu berfungsi dengan baik! :-)
Manish
Jika tidak berhasil, mungkin karena lokalisasi. Coba {{my_num | intcomma: False}} dalam kasus itu
Jose Cherian
105

Membangun jawaban lain, untuk memperluas ini ke mengapung, Anda dapat melakukan:

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

Dokumentasi: floatformat, intcomma.

Vinod Kurup
sumber
59

Mengenai solusi Ned Batchelder, ini dia dengan 2 poin desimal dan tanda dolar. Ini seperti di suatu tempatmy_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)

Maka kamu bisa

{% load my_filters %}
{{my_dollars | currency}}
Dave Aaron Smith
sumber
3
Bug pada kode di atas, coba ini:>>> currency(0.99958) u'$0.00'
Ahsan
1
Kode ini harus masuk dalam file sendiri di [proyek_anda] / [nama_anda] / templatetags / [nama file] .py. Maka harus dimuat dalam templat dengan {% load [filtername]%}. Lihat docs.djangoproject.com/en/1.10/howto/custom-template-tags untuk informasi yang lebih bermanfaat dan spesifik.
mayypile
20

Coba tambahkan baris berikut di settings.py:

USE_THOUSAND_SEPARATOR = True

Ini seharusnya bekerja.

Lihat dokumentasi .


pembaruan pada 2018-04-16:

Ada juga cara python untuk melakukan hal ini:

>>> '{:,}'.format(1000000)
'1,000,000'
karton
sumber
10
Hati-hati saat menggunakan ini. Juga akan memformat angka dalam url dan lainnya yang Anda tambahkan ke template
Christoffer
4
Saya tidak bisa cukup menekankan komentar @Christoffer - dalam template di mana id diberikan dan digunakan dalam tautan, ini dapat menyebabkan sakit kepala besar!
LaundroMat
Ini tidak sesuai untuk templat Django
Ben
@ Ben mana yang tidak pantas? "the python way" atau seribu bendera pemisah dalam pengaturan? seribu bendera pemisah harus berfungsi dengan baik untuk templat Django. Apa versi Django Anda?
carton.swing
1
Format string (python) seperti itu karena Anda tidak dapat menggunakan ini secara langsung dalam template - Anda harus meletakkan ini dalam tag template (yang merupakan jawaban yang baik), tetapi hanya membuang ini tidak banyak digunakan sebagai jawaban yang lengkap.
Ben
11

Jika Anda tidak ingin terlibat dengan lokal di sini adalah fungsi yang memformat angka:

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)

Membuat filter templat khusus dari fungsi ini sepele.

muhuk
sumber
10

The memanusiakan solusi baik-baik saja jika website Anda dalam bahasa Inggris. Untuk bahasa lain, Anda memerlukan solusi lain: Saya sarankan menggunakan Babel . Salah satu solusinya adalah membuat tag templat khusus untuk menampilkan angka dengan benar. Begini caranya: cukup buat file berikut di 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)

Kemudian Anda dapat menggunakan tag templat ini dalam templat Anda seperti ini:

{% load sexy_number from sexify %}

{% sexy_number 1234.56 %}
  • Untuk pengguna Amerika (lokal en_US) ini menampilkan 1.234.56.
  • Untuk pengguna Perancis (locale fr_FR), ini menampilkan 1 234,56.
  • ...

Tentu saja Anda bisa menggunakan variabel sebagai gantinya:

{% sexy_number some_variable %}

Catatan: yang contextparameter saat ini tidak digunakan dalam contoh saya, tapi saya menaruhnya di sana untuk menunjukkan bahwa Anda dapat dengan mudah men-tweak tag template ini untuk membuatnya menggunakan apa pun yang dalam konteks Template.

MiniQuark
sumber
1
lokal saya adalah 'pt_BR' dan "intcomma" berfungsi bahkan di Brasil sebagai pemisahan oleh '.' dan bukan dengan ',' menjadi floatvalue = 25000.35 {{floatvalue | intcomma}} menghasilkan 25000.35
Zokis
Anda benar, tetapi format ini tidak sesuai dengan pemisah ribuan (25.000,35 untuk en_US dan 25 000,35 untuk fr_FR).
MiniQuark
4

The memanusiakan app menawarkan bagus dan cara cepat format nomor tetapi jika Anda perlu menggunakan berbeda pemisah dari koma, sederhana itu hanya menggunakan kembali kode dari aplikasi memanusiakan , ganti char pemisah, dan membuat filter khusus . Misalnya, gunakan ruang sebagai pemisah:

@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
sumber
Terima kasih. Saya membutuhkan versi dot dan saran Anda menyelamatkan saya! Bersulang!
kstratis
3

Sedikit topik:

Saya menemukan pertanyaan ini sambil mencari cara untuk memformat angka sebagai mata uang, seperti:

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

Saya akhirnya melakukan:

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

Anda juga dapat melakukan, misalnya {{ var|stringformat:"1.2f"|cut:"-" }}menampilkan sebagai$50.00 (dengan 2 tempat desimal jika itu yang Anda inginkan.

Mungkin sedikit di sisi hacky, tetapi mungkin orang lain akan merasa berguna.

Felix Böhme
sumber
2

Yah saya tidak bisa menemukan cara Django, tetapi saya memang menemukan cara python dari dalam model saya:

def format_price(self):
    import locale
    locale.setlocale(locale.LC_ALL, '')
    return locale.format('%d', self.price, True)
Oli
sumber
Hmm - ini telah -1'd, tanpa penjelasan - tidak membantu. Bagi mereka yang berpikir jawabannya salah dalam beberapa hal, tolong katakan mengapa untuk kepentingan penjawab dan pembaca. Saya kira saya bukan penggemar pengaturan lokal (yang global dalam jangkauan), dalam fungsi yang satu ini (sisi yang tidak menyenangkan mempengaruhi mendapatkan mata uang) - yang bisa menjelaskan -1.
Danny Staple
Saya melakukan -1 detik - seperti yang dijelaskan dalam prev. komentar, itu s really not correct not giving any reason. Here itmudah: Django telah mendapat template khusus (mirip dengan Jinja2 - atau Jinja2) yang tidak memungkinkan fungsi python standar. Jadi jawaban ini sama sekali tidak berguna. Terlebih lagi, Django memiliki fungsi sendiri dalam mengelola ini dan menulis sesuatu yang baru yang berfungsi adalah ide yang tidak baik ...
tomis
2
Saya tidak setuju dengan downvoters - memastikan nilai diformat dengan benar dalam fungsi tampilan sebelum menyentuh template sepertinya pendekatan yang benar-benar valid.
Paul Tomblin
1

Perlu diketahui bahwa mengubah lokal adalah proses-lebar dan tidak aman thread (iow., Dapat memiliki efek samping atau dapat mempengaruhi kode lain yang dieksekusi dalam proses yang sama).

Proposisi saya: lihat paket Babel . Beberapa cara mengintegrasikan dengan template Django tersedia.

zgoda
sumber
1

Berdasarkan jawaban muhuk saya melakukan string.formatmetode enkapsulasi tag python sederhana ini .

  • Membuat templatetags di folder aplikasi Anda.
  • Buat format.pyfile di atasnya.
  • Tambahkan ini ke dalamnya:

    from django import template
    
    register = template.Library()
    
    @register.filter(name='format')
    def format(value, fmt):
        return fmt.format(value)
  • Muat di templat Anda {% load format %}
  • Gunakan. {{ some_value|format:"{:0.2f}" }}
tokek
sumber