Formato de números en plantillas django

154

Estoy tratando de formatear números. Ejemplos:

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

Parece algo bastante común, pero no puedo entender qué filtro se supone que debo usar.

Editar: si tiene una forma genérica de Python para hacer esto, me complace agregar un campo formateado en mi modelo.

Oli
fuente
3
Tenga cuidado si sus usuarios objetivo también están en Europa. Algunos países europeos como Alemania usan, como marca decimal.
tobltobs

Respuestas:

312

La aplicación de humanización contribuida de Django hace esto:

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

Asegúrese de agregar 'django.contrib.humanize'a su INSTALLED_APPSlista en el settings.pyarchivo.

Ned Batchelder
fuente
17
¿Hay alguna razón por la cual estos pocos filtros simples no son parte de los filtros incorporados?
PawelRoman
8
@PawelRoman Para evitar la carga de un montón de filtros y etiquetas que rara vez se usan (y así hacer que la representación de la plantilla sea más rápida)
Maxime Lorant
Agregué 'django.contrib.humanize' en INSTALLED_APPS y también incluí {% load humanize%} en mi plantilla y reinicié el servidor. Sin embargo, cuando trato de usar el filtro "intcomma", aparece este error: Filtro no válido: 'intcomma' El rastreo de depuración muestra 'django.contrib.humanize' incluido en settings.py. ¿Cuál podría ser el posible problema?
Manish
1
Tengo respuesta a mi propio problema aquí: había incluido {% load humanize%} en la plantilla base (ya que la necesito para muchas plantillas). Parece que no funciona: cuando lo agregué en las plantillas relevantes, ¡funcionó bien! :-)
Manish
Si no funciona, podría deberse a la localización. Pruebe {{my_num | intcomma: False}} en ese caso
Jose Cherian
105

Sobre la base de otras respuestas, para extender esto a las carrozas, puede hacer:

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

Documentación: floatformat, intcomma.

Vinod Kurup
fuente
59

Con respecto a la solución de Ned Batchelder, aquí está con 2 puntos decimales y un signo de dólar. Esto va a algún lado comomy_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)

Entonces tú puedes

{% load my_filters %}
{{my_dollars | currency}}
Dave Aaron Smith
fuente
3
Error en el código anterior, intente esto:>>> currency(0.99958) u'$0.00'
Ahsan
1
Este código debe ir en su propio archivo en [your_project] / [your_app] / templatetags / [filtername] .py. Luego se debe cargar en la plantilla con {% load [filtername]%}. Consulte docs.djangoproject.com/en/1.10/howto/custom-template-tags para obtener más información útil y específica.
mightypile
20

Intente agregar la siguiente línea en settings.py:

USE_THOUSAND_SEPARATOR = True

Esto debería funcionar.

Consulte la documentación .


actualización en 2018-04-16:

También hay una forma de Python para hacer esto:

>>> '{:,}'.format(1000000)
'1,000,000'
carton.swing
fuente
10
Tenga cuidado al usar esto. También formateará números en URL y otros que agregue a la plantilla
Christoffer el
44
No puedo enfatizar lo suficiente el comentario de @Christoffer: en las plantillas en las que se muestran y usan los ID en los enlaces, ¡esto puede causar grandes dolores de cabeza!
LaundroMat
Esto no es apropiado para las plantillas de Django
Ben
@Ben que no es apropiado? "la manera de python" o la bandera de mil separadores en la configuración? el indicador de mil separadores debería funcionar bien para las plantillas de Django. ¿Cuál es la versión de su Django?
carton.swing
1
La forma del formato de cadena (la pitón) porque no puede usar esto directamente en las plantillas: tendría que poner esto en una etiqueta de plantilla (que es una buena respuesta), pero tirar esto es de poca utilidad como respuesta completa.
Ben
11

Si no desea involucrarse con las configuraciones regionales, aquí hay una función que formatea los números:

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)

Crear un filtro de plantilla personalizado a partir de esta función es trivial.

muhuk
fuente
10

La solución humanize está bien si su sitio web está en inglés. Para otros idiomas, necesita otra solución: recomiendo usar Babel . Una solución es crear una etiqueta de plantilla personalizada para mostrar los números correctamente. Así es como: simplemente cree el siguiente archivo en 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)

Luego puede usar esta etiqueta de plantilla en sus plantillas de esta manera:

{% load sexy_number from sexify %}

{% sexy_number 1234.56 %}
  • Para un usuario estadounidense (locale en_US), esto muestra 1,234.56.
  • Para un usuario francés (locale fr_FR), esto muestra 1 234,56.
  • ...

Por supuesto, puede usar variables en su lugar:

{% sexy_number some_variable %}

Nota: el contextparámetro no se usa actualmente en mi ejemplo, pero lo puse allí para mostrar que puede ajustar fácilmente esta etiqueta de plantilla para que use cualquier cosa que esté en el contexto de la plantilla.

MiniQuark
fuente
1
mi locale es 'pt_BR' y "intcomma" funciona incluso en Brasil siendo la separación por '.' y no por ',' siendo floatvalue = 25000.35 {{floatvalue | intcomma}} da como resultado 25000.35
Zokis
Tiene razón, pero este formato no es apropiado con respecto al separador de miles (25,000.35 para en_US y 25 000,35 para fr_FR).
MiniQuark
4

La aplicación humanize ofrece una forma agradable y rápida de formatear un número, pero si necesita usar un separador diferente de la coma, es simple reutilizar el código de la aplicación humanize , reemplazar el separador char y crear un filtro personalizado . Por ejemplo, use el espacio como separador:

@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
fuente
Gracias. ¡Necesitaba una versión de puntos y su sugerencia me salvó! ¡Salud!
kstratis
3

Ligeramente fuera de tema:

Encontré esta pregunta mientras buscaba una forma de formatear un número como moneda, así:

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

Terminé haciendo:

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

También podría hacerlo, por ejemplo, {{ var|stringformat:"1.2f"|cut:"-" }}para mostrar como $50.00(con 2 decimales si eso es lo que desea).

Quizás un poco hacky, pero quizás alguien más lo encuentre útil.

Felix Böhme
fuente
2

Bueno, no pude encontrar una forma de Django, pero sí encontré una forma de Python desde el interior de mi modelo:

def format_price(self):
    import locale
    locale.setlocale(locale.LC_ALL, '')
    return locale.format('%d', self.price, True)
Oli
fuente
Hmm, esto ha sido -1, sin explicación, inútil. Para aquellos que piensan que la respuesta es incorrecta de alguna manera, sírvanse decir por qué en beneficio del respondedor y los lectores. Supongo que no soy fanático de establecer la configuración regional (que es de alcance global), en esta función (efecto secundario desagradable de obtener la moneda), lo que podría explicar el -1.
Danny Staple
Hice el segundo -1, como se describe en el anterior. comentario, s really not correct not giving any reason. Here ites fácil: Django tiene una plantilla específica (similar a Jinja2, o es Jinja2) que no permite las funciones estándar de Python. Entonces esta respuesta no es útil en absoluto. Lo que es más funciones propias, Django ha conseguido la gestión de este y escribiendo nada nuevo lo que está funcionando realmente no es buena idea ...
Tomis
2
No estoy de acuerdo con los downvoters: asegurarse de que el valor esté formateado correctamente en la función de vista antes de que llegue a la plantilla parece un enfoque perfectamente válido.
Paul Tomblin
1

Tenga en cuenta que cambiar la configuración regional es para todo el proceso y no es seguro para subprocesos (por ejemplo, puede tener efectos secundarios o puede afectar a otro código ejecutado dentro del mismo proceso).

Mi propuesta: mira el paquete de Babel . Existen algunos medios para integrarse con las plantillas de Django.

zgoda
fuente
1

Basado en la respuesta muhuk, hice este string.formatmétodo simple de encapsulación de python .

  • Cree una templatetagscarpeta de aplicaciones en su.
  • Crea un format.pyarchivo en él.
  • Agregue esto:

    from django import template
    
    register = template.Library()
    
    @register.filter(name='format')
    def format(value, fmt):
        return fmt.format(value)
  • Cárgalo en tu plantilla {% load format %}
  • Úsalo. {{ some_value|format:"{:0.2f}" }}
gecos
fuente