Formatta i numeri nei modelli di django


153

Sto cercando di formattare i numeri. Esempi:

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

Sembra una cosa abbastanza comune da fare ma non riesco a capire quale filtro dovrei usare.

Modifica: se hai un modo Python generico per farlo, sono felice di aggiungere un campo formattato nel mio modello.


3
Fai attenzione se i tuoi utenti target sono anche in Europa. Alcuni paesi europei come la Germania usano, come segno decimale.
tobltobs,

Risposte:


313

L' applicazione umanizzata fornita da Django fa questo:

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

Assicurati di aggiungere 'django.contrib.humanize'alla tua INSTALLED_APPSlista nel settings.pyfile.


17
C'è un motivo per cui questi pochi semplici filtri non fanno parte dei filtri integrati?
PawelRoman,

8
@PawelRoman Per evitare il caricamento di un sacco di filtri e tag usati raramente (e quindi rendere più veloce il rendering del modello)
Maxime Lorant,

Ho aggiunto 'django.contrib.humanize' in INSTALLED_APPS e ho anche incluso {% load humanize%} nel mio modello e ho riavviato il server. Tuttavia, quando provo ad usare il filtro "intcomma", ottengo questo errore - Filtro non valido: 'intcomma' La traccia di debug mostra 'django.contrib.humanize' incluso in settings.py. Quale potrebbe essere il possibile problema?
Manish

1
Ho ottenuto la risposta al mio problema qui: avevo incluso {% load humanize%} nel modello di base (dal momento che ne ho bisogno per molti modelli). Sembra che non funzioni - quando l'ho aggiunto nei modelli pertinenti, ha funzionato bene! :-)
Manish

Se non funziona, potrebbe essere dovuto alla localizzazione. Prova {{my_num | intcomma: False}} in quel caso
Jose Cherian il

105

Sulla base di altre risposte, per estenderlo ai float, puoi fare:

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

Documentazione: floatformat, intcomma.


59

Per quanto riguarda la soluzione di Ned Batchelder, eccola con 2 punti decimali e un segno di dollaro. Questo va da qualche parte comemy_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)

Allora puoi

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

3
Bug sul codice sopra, prova questo:>>> currency(0.99958) u'$0.00'
Ahsan

1
Questo codice dovrebbe andare nel suo file in [your_project] / [your_app] / templatetags / [filtername] .py. Dovrebbe quindi essere caricato nel modello con {% load [nome file]%}. Consulta docs.djangoproject.com/en/1.10/howto/custom-template-tags per informazioni più utili e specifiche.
poderoso

20

Prova ad aggiungere la seguente riga in settings.py:

USE_THOUSAND_SEPARATOR = True

Questo dovrebbe funzionare.

Fare riferimento alla documentazione .


aggiornamento al 16-04-2018:

C'è anche un modo Python per fare questa cosa:

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

10
Fai attenzione quando lo usi. Formatterà anche i numeri negli URL e altro che aggiungi al modello
Christoffer,

4
Non posso sottolineare abbastanza il commento di @Christoffer - nei modelli in cui gli ID sono resi e usati nei link, questo può causare grossi mal di testa!
LaundroMat,

Questo non è appropriato per i modelli Django
Ben

@Ben che non è appropriato? "the python way" o il flag del separatore dei mille nelle impostazioni? la bandiera dei mille separatori dovrebbe funzionare bene per i modelli di Django. qual è la tua versione di Django?
carton.swing

1
Il formato stringa (il pitone) perché non puoi usarlo direttamente nei template - dovresti metterlo in un tag template (che è una buona risposta), ma buttarlo fuori è di scarsa utilità come risposta completa.
Ben

11

Se non vuoi essere coinvolto nelle impostazioni locali, ecco una funzione che formatta i numeri:

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)

La creazione di un filtro modello personalizzato da questa funzione è banale.


10

La soluzione umanizzare va bene se il tuo sito web è in inglese. Per altre lingue, hai bisogno di un'altra soluzione: ti consiglio di usare Babel . Una soluzione è quella di creare un tag modello personalizzato per visualizzare correttamente i numeri. Ecco come: basta creare il seguente 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)

Quindi puoi utilizzare questo tag modello nei tuoi modelli in questo modo:

{% load sexy_number from sexify %}

{% sexy_number 1234.56 %}
  • Per un utente americano (locale en_US) viene visualizzato 1.234,56.
  • Per un utente francese (locale fr_FR), viene visualizzato 1 234,56.
  • ...

Ovviamente puoi usare invece le variabili:

{% sexy_number some_variable %}

Nota: il contextparametro non è attualmente utilizzato nel mio esempio, ma l'ho messo lì per mostrare che puoi facilmente modificare questo tag modello per farlo usare tutto ciò che è nel contesto del modello.


1
la mia locale è 'pt_BR' e "intcomma" funziona anche in Brasile essendo la separazione per '.' e non per ',' essendo floatvalue = 25000.35 {{floatvalue | intcomma}} risulta in 25000.35
Zokis

Hai ragione, ma questo formato non è appropriato per quanto riguarda il separatore delle migliaia (25.000,35 per en_US e 25000,35 per fr_FR).
MiniQuark

4

L' app Humanize offre un modo semplice e veloce per formattare un numero ma se devi usare un separatore diverso dalla virgola, è semplice riutilizzare il codice dall'app Humanize , sostituire il carattere separatore e creare un filtro personalizzato . Ad esempio, utilizzare lo spazio come separatore:

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

Grazie. Avevo bisogno di una versione dot e il tuo suggerimento mi ha salvato! Saluti!
kstratis,

3

Leggermente fuori tema:

Ho trovato questa domanda mentre cercavo un modo per formattare un numero come valuta, in questo modo:

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

Ho finito per fare:

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

Si potrebbe anche fare, ad esempio {{ var|stringformat:"1.2f"|cut:"-" }}per visualizzare come$50.00 (con 2 cifre decimali se è quello che si desidera.

Forse un po 'confuso, ma forse qualcun altro lo troverà utile.


2

Beh, non sono riuscito a trovare un modo Django, ma ho trovato un modo pitone dall'interno del mio modello:

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

Hmm - questo è stato -1, senza alcuna spiegazione - inutile. Per coloro che pensano che la risposta sia errata in qualche modo, si prega di dire perché a beneficio di chi risponde e dei lettori. Suppongo di non essere un fan dell'impostazione del locale (che è di portata globale), in questa funzione (effetto spiacevole di ottenere la valuta) - che potrebbe spiegare -1.
Danny Staple,

Ho fatto il secondo -1 - come descritto in anteprima. commentare, è s really not correct not giving any reason. Here itfacile: Django ha un modello specifico (simile a Jinja2 - o è Jinja2) che non consente le funzioni standard di Python. Quindi questa risposta non è affatto utile. Inoltre, Django ha le proprie funzioni per gestire questo e scrivere qualcosa di nuovo, ciò che funziona non è davvero una buona idea ...
Tomis,

2
Non sono d'accordo con i downvoter: assicurarsi che il valore sia formattato correttamente nella funzione di visualizzazione prima che colpisca il modello sembra un approccio perfettamente valido.
Paul Tomblin,

1

Tenere presente che la modifica delle impostazioni internazionali è a livello di processo e non è sicura per i thread (iow., Può avere effetti collaterali o influire su altro codice eseguito all'interno dello stesso processo).

La mia proposta: controlla il pacchetto Babel . Sono disponibili alcuni mezzi per l'integrazione con i modelli Django.



1

Sulla base della risposta muhuk ho fatto questo semplice tag incapsulando il string.formatmetodo Python .

  • Crea un templatetagsnella cartella delle applicazioni.
  • Crea un format.pyfile su di esso.
  • Aggiungi questo ad esso:

    from django import template
    
    register = template.Library()
    
    @register.filter(name='format')
    def format(value, fmt):
        return fmt.format(value)
  • Caricalo nel tuo modello {% load format %}
  • Usalo {{ some_value|format:"{:0.2f}" }}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.