'Django Decimal field with value Decimal(0.00) is displayed as 0E-10 in the Django Admin Inline

Django 2.2. Model Definition.

class BlockPeriod(BaseModel):
    price = models.DecimalField(max_digits=20, decimal_places=10)
    margin = models.DecimalField(max_digits=20, decimal_places=10)

If the user saves margin or price as "0" it would be displayed as "OE-10" on the next page load.

Screenshot is from DjangoAdmin.

enter image description here

I want to display 0 or 0.00 instead of OE-10 in margin and price fields.

Thanks



Solution 1:[1]

If you only want to display 2 places, you can simply set decimal_places to 2.

class BlockPeriod(BaseModel):
    price = models.DecimalField(max_digits=20, decimal_places=2)
    margin = models.DecimalField(max_digits=20, decimal_places=2)

You can also consider using a FloatField which leads to 0.0 as representation for 0.

float_value = models.FloatField()

Solution 2:[2]

The way out of it was adding form fields price and margin with decimal places set to 6. For any number higher Django renders inline fields with html step "1e-7","1e-8", "1e-9"... I wanted to keep 10 decimal places on DB level.

Solution 3:[3]

I solved this by creating a custom admin form widget that replaces 0E-10 with 0 using JavaScript. Here is the Django part:

from django import forms
from django.contrib import admin

class BlockPeriod(BaseModel):
    price = models.DecimalField(max_digits=20, decimal_places=10)
    margin = models.DecimalField(max_digits=20, decimal_places=10)

class DecimalWidget(forms.widgets.NumberInput):
    class Media:
        js = ('js/decimal_widget.js', )
        
class BlockPeriodAdminForm(forms.ModelForm):
    class Meta:
        widget = DecimalWidget(attrs={'class': 'decimal-widget'})
        widgets = {'price': widget, 'margin': widget}
        fields = '__all__'

class BlockPeriodAdmin(admin.ModelAdmin):
    form = BlockPeriodAdminForm

admin.site.register(BlockPeriod, BlockPeriodAdmin)

Then somewhere under static/js/decimal_widget.js (your file location may be different) you would have this JavaScript:

function convertDecimalValues() {
  $('input.decimal-widget').each(function() {
    if (this.value == '0E-10') { this.value = 0; }
  });
}

$(document).ready(function() {
  convertDecimalValues();
});

I will be the first to admit that this feels like an overkill, and there should be an easier way to do this. But this does the trick.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sören
Solution 2 Yuri Kots
Solution 3 Sergei Krupenin