Mehdi Aria
Mehdi Aria

Reputation: 161

Django create a custom model field for currencies

Here I my custom model field I created it

class CurrencyAmountField(models.DecimalField):
    INTEGER_PLACES = 5
    DECIMAL_PLACES = 5

    DECIMAL_PLACES_FOR_USER = 2

    MAX_DIGITS = INTEGER_PLACES + DECIMAL_PLACES

    MAX_VALUE = Decimal('99999.99999')
    MIN_VALUE = Decimal('-99999.99999')

    def __init__(self, verbose_name=None, name=None, max_digits=MAX_DIGITS,
                 decimal_places=DECIMAL_PLACES, **kwargs):
        super().__init__(verbose_name=verbose_name, name=name, max_digits=max_digits,
                         decimal_places=decimal_places, **kwargs)

How can I show the numbers in a comma-separated mode in Django admin forms? Should I override some method here on this custom model field or there is another to do that?

enter image description here

Should be:

enter image description here

Update:

Tried to use intcomma like this:

{% extends "admin/change_form.html" %}
{% load humanize %}
{% block field_sets %}

 {% for fieldset in adminform %}
  <fieldset class="module aligned {{ fieldset.classes }}">
    {% if fieldset.name %}<h2>{{ fieldset.name }}</h2>{% endif %}
    {% if fieldset.description %}
        <div class="description">{{ fieldset.description|safe }}</div>
    {% endif %}
    {% for line in fieldset %}
        <div class="form-row{% if line.fields|length_is:'1' and line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}">
            {% if line.fields|length_is:'1' %}{{ line.errors }}{% endif %}
            {% for field in line %}
                <div{% if not line.fields|length_is:'1' %} class="fieldBox{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if not field.is_readonly and field.errors %} errors{% endif %}{% if field.field.is_hidden %} hidden{% endif %}"{% elif field.is_checkbox %} class="checkbox-row"{% endif %}>
                    {% if not line.fields|length_is:'1' and not field.is_readonly %}{{ field.errors }}{% endif %}
                    {% if field.is_checkbox %}
                        {{ field.field }}{{ field.label_tag }}
                    {% else %}
                        {{ field.label_tag }}
                        {% if field.is_readonly %}
                            <div class="readonly">{{ field.contents }}</div>
                        {% else %}
                            {{ field.field|intcomma }}
                        {% endif %}
                    {% endif %}
                    {% if field.field.help_text %}
                        <div class="help">{{ field.field.help_text|safe }}</div>
                    {% endif %}
                </div>
            {% endfor %}
        </div>
    {% endfor %}
</fieldset>
{% endfor %}
{% endblock %}

As you can see I added intcomma like this: {{ field.field|intcomma }} But I get HTML codes on my admin page instead of the forms and labels. What's wrong here?

My priority is to use the first method and 'CurrencyAmountField'.

Upvotes: 4

Views: 747

Answers (2)

afterburner
afterburner

Reputation: 2781

While I have yet to manage to get the comma to display on input, I have managed to get the comma to display when viewing the saved model

This is what I have tried currently

# forms.py
class ValuesForm(forms.ModelForm):
    class Meta:
        model = Values
        fields = ['value']

    value = forms.DecimalField(localize=True)


#settings.py
USE_THOUSAND_SEPARATOR = True

#admin.py
class ValuesAdmin(admin.ModelAdmin):
    form = ValuesForm

#models.py
class Values(models.Model):
    value = models.DecimalField(max_digits=10, decimal_places=2

While documentation suggests it's possible to do it on input, it might require a custom widget, so I'll investigate that shortly.

As a working solution, I have replaced the comma with _ when inputting, manually.

e.g. 12_345_678 which gets displayed on save as 12,345,678

Upvotes: 1

Maxim Danilov
Maxim Danilov

Reputation: 3350

First:

MAX_VALUE = Decimal('99999.99999')

90.000 < 333.222.111 It gives you validation error if you write 333222111. In your question you use this number.

Second:

on image you have input and textarea. To get a textarea you should change widget = TextInput in field.

class CurrencyAmountField(models.DecimalField):
    widget = Textarea

You can do it also in form. You can do it also in modelAdmin. And you dont need your own Field class.

Third:

you can use MaxValueValidator, MinValueValidator instead of MAX_VALUE, after that - you don't need to create you own field class.

myAmount = DecimalField(max_digits=10, decimal_places=5, validators=[MaxValueValidator(Decimal('99999.99999')), MinValueValidator(Decimal('-99999.99999'))])

Four:

check your settings. more here: https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-USE_THOUSAND_SEPARATOR

USE_THOUSAND_SEPARATOR, USE_L10N, NUMBER_GROUPING, THOUSAND_SEPARATOR please write it in your question.

And you don't need to change any html-template, everything can be done in python.

in additional

we can improve our input html tag with small js:

onkeyup="this.value=Number(this.value).toLocaleString('de-At', {minimumFractionDigits: 2});"
// or 
onkeyup="this.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");"

The both js solution you should rewrite for your project:

  • The first one should check your country settings and decimal_places

  • The second should use localized separator for thousands and for decimal_places.

Last part i have from answers here: How to print a number with commas as thousands separators in JavaScript

Upvotes: 3

Related Questions