Mettre en forme les nombres dans les modèles Django


153

J'essaye de formater les nombres. Exemples:

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

Cela semble être une chose assez courante à faire, mais je ne sais pas quel filtre je suis censé utiliser.

Edit: Si vous avez une façon générique de faire cela en Python, je suis heureux d'ajouter un champ formaté dans mon modèle.


3
Soyez prudent si vos utilisateurs cibles se trouvent également en Europe. Certains pays européens comme l'Allemagne utilisent, comme signe décimal.
tobltobs

Réponses:


313

L' application humanize fournie par Django fait ceci:

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

Assurez-vous d'ajouter 'django.contrib.humanize'à votre INSTALLED_APPSliste dans le settings.pyfichier.


17
Y a-t-il une raison pour laquelle ces quelques filtres simples ne font pas partie des filtres intégrés?
PawelRoman

8
@PawelRoman Pour éviter le chargement d'un tas de filtres et de balises rarement utilisés (et ainsi rendre le rendu du template plus rapide)
Maxime Lorant

J'ai ajouté 'django.contrib.humanize' dans INSTALLED_APPS et j'ai également inclus {% load humanize%} dans mon modèle et j'ai redémarré le serveur. Cependant, quand j'essaye d'utiliser le filtre "intcomma", j'obtiens cette erreur - Filtre invalide: "intcomma" La trace de débogage montre "django.contrib.humanize" inclus dans settings.py. Quel pourrait être le problème éventuel?
Manish

1
J'ai une réponse à mon propre problème ici - j'avais inclus {% load humanize%} dans le modèle de base (puisque j'en ai besoin pour beaucoup de modèles). Il semble que cela ne fonctionne pas - quand je l'ai ajouté dans les modèles appropriés, cela a bien fonctionné! :-)
Manish

Si cela ne fonctionne pas, cela peut être dû à la localisation. Essayez {{my_num | intcomma: False}} dans ce cas
Jose Cherian le

105

En vous basant sur d'autres réponses, pour étendre cela aux flotteurs, vous pouvez faire:

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

Documentation: floatformat, intcomma.


59

Concernant la solution de Ned Batchelder, la voici avec 2 décimales et un signe dollar. Cela va quelque part commemy_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)

Ensuite vous pouvez

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

3
Bug sur le code ci-dessus, essayez ceci:>>> currency(0.99958) u'$0.00'
Ahsan

1
Ce code doit aller dans son propre fichier à [votre_projet] / [votre_app] / templatetags / [nom_fichier] .py. Il doit ensuite être chargé dans le modèle avec {% load [filtername]%}. Voir docs.djangoproject.com/en/1.10/howto/custom-template-tags pour des informations plus utiles et spécifiques.
mightypile

20

Essayez d'ajouter la ligne suivante dans settings.py:

USE_THOUSAND_SEPARATOR = True

Cela devrait fonctionner.

Reportez-vous à la documentation .


mise à jour le 16/04/2018:

Il existe également un moyen python de faire cette chose:

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

10
Soyez prudent lorsque vous l'utilisez. Formatera également les nombres dans les URL et autres que vous ajoutez au modèle
Christoffer

4
Je ne saurais trop insister sur le commentaire de @Christoffer - dans les modèles où les identifiants sont rendus et utilisés dans les liens, cela peut causer de gros maux de tête!
LaundroMat du

Ce n'est pas approprié pour les modèles Django
Ben

@Ben ce qui n'est pas approprié? "la manière python" ou le drapeau séparateur des milliers dans les paramètres? l'indicateur de séparation des milliers doit être bien adapté aux modèles Django. Quelle est la version de votre Django?
carton.swing

1
Le format de chaîne (le python) parce que vous ne pouvez pas l'utiliser directement dans les modèles - vous devriez le mettre dans une balise de modèle (ce qui est une bonne réponse), mais le simple fait de le jeter est peu utile comme réponse complète.
Ben

11

Si vous ne voulez pas vous impliquer dans les paramètres régionaux, voici une fonction qui formate les nombres:

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 création d'un filtre de modèle personnalisé à partir de cette fonction est triviale.


10

La solution humanize convient si votre site Web est en anglais. Pour les autres langues, vous avez besoin d'une autre solution: je recommande d'utiliser Babel . Une solution consiste à créer une balise de modèle personnalisée pour afficher correctement les nombres. Voici comment: créez simplement le fichier suivant dans 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)

Ensuite, vous pouvez utiliser cette balise de modèle dans vos modèles comme ceci:

{% load sexy_number from sexify %}

{% sexy_number 1234.56 %}
  • Pour un utilisateur américain (locale en_US), cela affiche 1 234,56.
  • Pour un utilisateur français (locale fr_FR), cela affiche 1 234,56.
  • ...

Bien sûr, vous pouvez utiliser des variables à la place:

{% sexy_number some_variable %}

Remarque: le contextparamètre n'est actuellement pas utilisé dans mon exemple, mais je l'ai mis là pour montrer que vous pouvez facilement modifier cette balise de modèle pour qu'elle utilise tout ce qui se trouve dans le contexte du modèle.


1
ma langue est 'pt_BR' et "intcomma" fonctionne même au Brésil étant la séparation par '.' et pas par ',' étant floatvalue = 25000.35 {{floatvalue | intcomma}} donne 25000.35
Zokis

Vous avez raison, mais ce format n'est pas approprié pour le séparateur des milliers (25 000,35 pour en_US et 25 000,35 pour fr_FR).
MiniQuark

4

L' application humanize offre un moyen agréable et rapide de formater un nombre, mais si vous devez utiliser un séparateur différent de la virgule, il est simple de réutiliser simplement le code de l'application humanize , de remplacer le caractère de séparation et de créer un filtre personnalisé . Par exemple, utilisez l' espace comme séparateur:

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

Merci. J'avais besoin d'une version dot et votre suggestion m'a sauvé! À votre santé!
kstratis

3

Légèrement hors sujet:

J'ai trouvé cette question en cherchant un moyen de formater un nombre en tant que devise, comme ceci:

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

J'ai fini par faire:

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

Vous pouvez également faire, par exemple {{ var|stringformat:"1.2f"|cut:"-" }}pour afficher comme $50.00(avec 2 décimales si c'est ce que vous voulez.

Peut-être légèrement sur le côté hacky, mais peut-être que quelqu'un d'autre le trouvera utile.


2

Eh bien, je n'ai pas pu trouver un moyen Django, mais j'ai trouvé un moyen python à l'intérieur de mon modèle:

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

Hmm - cela a été -1'd, sans explication - inutile. Pour ceux qui pensent que la réponse est incorrecte d'une manière ou d'une autre, veuillez expliquer pourquoi pour le bénéfice du répondant et des lecteurs. Je suppose que je ne suis pas fan du réglage de la locale (qui est globale), dans cette fonction (effet secondaire désagréable d'obtenir la devise) - ce qui pourrait expliquer le -1.
Danny Staple

J'ai fait la seconde -1 - comme décrit dans la précédente. commentaire, c'est s really not correct not giving any reason. Here itfacile: Django a un template spécifique (similaire à Jinja2 - ou c'est Jinja2) qui n'autorise pas les fonctions python standard. Cette réponse n'est donc pas du tout utile. De plus, Django a ses propres fonctions pour gérer cela et écrire quoi que ce soit de nouveau ce qui fonctionne n'est vraiment pas une bonne idée ...
tomis

2
Je ne suis pas d'accord avec les votes négatifs - s'assurer que la valeur est correctement formatée dans la fonction d'affichage avant qu'elle n'atteigne le modèle semble être une approche parfaitement valide.
Paul Tomblin

1

Sachez que le changement de paramètres régionaux concerne l'ensemble du processus et n'est pas sûr pour les threads (iow., Peut avoir des effets secondaires ou affecter un autre code exécuté dans le même processus).

Ma proposition: découvrez le package Babel . Certains moyens d'intégration avec les modèles Django sont disponibles.



1

Sur la base de la réponse de muhuk, j'ai fait cette simple balise encapsulant la string.formatméthode python .

  • Créez un templatetagsdossier d'application de votre.
  • Créez un format.pyfichier dessus.
  • Ajoutez-y ceci:

    from django import template
    
    register = template.Library()
    
    @register.filter(name='format')
    def format(value, fmt):
        return fmt.format(value)
  • Chargez-le dans votre modèle {% load format %}
  • Utilise le. {{ some_value|format:"{:0.2f}" }}

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.