DecimalField Problem

1,978 views
Skip to first unread message

Timothy W. Cook

unread,
Jan 8, 2014, 10:18:50 AM1/8/14
to django...@googlegroups.com
I have several decimal fields defined in the model like this:

min_inclusive = models.DecimalField(_('minimum inclusive'), max_digits=19, decimal_places=10, help_text=_("Enter the minimum (inclusive) value for this concept."), null=True, blank=True)

Via the admin interface when I enter a 0 (zero)  and save the object I get 0E-10 as the value.  I am using PostgreSQL 9.1 for persistence. 

So, why doesn't it just store a zero? 

The documentation doesn't specify if decimal_places is forced or if it is a maximum number.  Is this display because 10 places are 'required'?  If so, the using the default form widget, TextInput, it seems to me that is should just expand to that size or at least scroll to that size.  

In reality I need to allow the range of,  positive infinity to negative infinity.  But this doesn't seem possible.  Is it?

Thanks,
Tim



--
MLHIM VIP Signup: http://goo.gl/22B0U
============================================
Timothy Cook, MSc           +55 21 94711995
MLHIM http://www.mlhim.org
Like Us on FB: https://www.facebook.com/mlhim2
Circle us on G+: http://goo.gl/44EV5
Google Scholar: http://goo.gl/MMZ1o
LinkedIn Profile:http://www.linkedin.com/in/timothywaynecook

Erik Cederstrand

unread,
Jan 8, 2014, 10:44:56 AM1/8/14
to Django Users
Den 08/01/2014 kl. 16.18 skrev Timothy W. Cook <t...@mlhim.org>:

> I have several decimal fields defined in the model like this:
>
> min_inclusive = models.DecimalField(_('minimum inclusive'), max_digits=19, decimal_places=10, help_text=_("Enter the minimum (inclusive) value for this concept."), null=True, blank=True)
>
> Via the admin interface when I enter a 0 (zero) and save the object I get 0E-10 as the value. I am using PostgreSQL 9.1 for persistence.
>
> So, why doesn't it just store a zero?

Underneath a DecimalField there is a Python float type, and some equivalent float type in your database. Float values are an approximation, so 0.000000000000 and 0 are not guaranteed to be equal. See http://stackoverflow.com/questions/2986150/python-floating-number

> In reality I need to allow the range of, positive infinity to negative infinity. But this doesn't seem possible. Is it?

It’s not physically or computationally possible. How will you store an infinite number of digits on a hard drive of finite size? :-)

Erik

Timothy W. Cook

unread,
Jan 8, 2014, 11:11:47 AM1/8/14
to django...@googlegroups.com
On Wed, Jan 8, 2014 at 1:44 PM, Erik Cederstrand <erik+...@cederstrand.dk> wrote:
Den 08/01/2014 kl. 16.18 skrev Timothy W. Cook <t...@mlhim.org>:

 
> So, why doesn't it just store a zero?

Underneath a DecimalField there is a Python float type, and some equivalent float type in your database. Float values are an approximation, so 0.000000000000 and 0 are not guaranteed to be equal. See http://stackoverflow.com/questions/2986150/python-floating-number


But one would think that if Django calls it a decimal field, it would convert the float to decimal. 
I suppose I'll do that before writing it out to the file (an XML schema) so it really isn't a big deal, just surprising. 

BTW: it is stored in PostgreSQL as 0.0000000000 as a numeric. 

 
> In reality I need to allow the range of,  positive infinity to negative infinity.  But this doesn't seem possible.  Is it?

It’s not physically or computationally possible. How will you store an infinite number of digits on a hard drive of finite size? :-)

Yeah, that was supposed to be sarcastic but it didn't come across well.  :-) 

 --Tim

Erik Cederstrand

unread,
Jan 8, 2014, 11:47:52 AM1/8/14
to Django Users
Den 08/01/2014 kl. 17.11 skrev Timothy W. Cook <t...@mlhim.org>:

> But one would think that if Django calls it a decimal field, it would convert the float to decimal.
> I suppose I'll do that before writing it out to the file (an XML schema) so it really isn't a big deal, just surprising.

Ah, the “decimal” in DecimalField only refers to how you are supposed to enter the values in a form. Python itself only has float and that’s what Django uses internally. Decimal vs. scientific notation is just a matter of how you choose to format the output when converting the float to a string. The default in Python depends on the value:

>>> str(0.1)
'0.1'
>>> str(0.00001)
'1e-05’

> > In reality I need to allow the range of, positive infinity to negative infinity. But this doesn't seem possible. Is it?
>
> It’s not physically or computationally possible. How will you store an infinite number of digits on a hard drive of finite size? :-)
>
> Yeah, that was supposed to be sarcastic but it didn't come across well. :-)

Sorry, I only do sarcasm in my native language :-)

Erik

Daniel Roseman

unread,
Jan 8, 2014, 11:56:13 AM1/8/14
to django...@googlegroups.com


On Wednesday, 8 January 2014 16:47:52 UTC, Erik Cederstrand wrote:
Den 08/01/2014 kl. 17.11 skrev Timothy W. Cook <t...@mlhim.org>:

> But one would think that if Django calls it a decimal field, it would convert the float to decimal.
> I suppose I'll do that before writing it out to the file (an XML schema) so it really isn't a big deal, just surprising.

Ah, the “decimal” in DecimalField only refers to how you are supposed to enter the values in a form. Python itself only has float and that’s what Django uses internally. Decimal vs. scientific notation is just a matter of how you choose to format the output when converting the float to a string. The default in Python depends on the value:

>>> str(0.1)
'0.1'
>>> str(0.00001)
'1e-05’

No, no, no. None of this is true.

Decimals are not a differently-formatted version of floats. Decimals are not a built-in datatype in Python, it's true, but they are provided in the standard library in (not surprisingly) the `decimal` module. As the documentation for that module explains, decimals do provide precise floating-point arithmetic, and are therefore suitable for representing things like currencies. Databases usually also provide a similar datatype, which Django's DecimalField maps to.
--
DR.

Timothy W. Cook

unread,
Jan 8, 2014, 12:56:45 PM1/8/14
to django...@googlegroups.com
On Wed, Jan 8, 2014 at 2:56 PM, Daniel Roseman <dan...@roseman.org.uk> wrote:

No, no, no. None of this is true.

Decimals are not a differently-formatted version of floats. Decimals are not a built-in datatype in Python, it's true, but they are provided in the standard library in (not surprisingly) the `decimal` module. As the documentation for that module explains, decimals do provide precise floating-point arithmetic, and are therefore suitable for representing things like currencies. Databases usually also provide a similar datatype, which Django's DecimalField maps to.

Thanks for this post Daniel.  I was just about to bring up the fact ath Python (since 2.4) has had decimals and does provide a library of operations for them.  http://docs.python.org/2/library/decimal.html 

Hence, my confusion about the DecimalField really using a float.

 

Erik Cederstrand

unread,
Jan 8, 2014, 3:07:07 PM1/8/14
to Django Users
Den 08/01/2014 kl. 17.56 skrev Daniel Roseman <dan...@roseman.org.uk>:
>
> No, no, no. None of this is true.
>
> Decimals are not a differently-formatted version of floats. Decimals are not a built-in datatype in Python, it's true, but they are provided in the standard library in (not surprisingly) the `decimal` module. As the documentation for that module explains, decimals do provide precise floating-point arithmetic, and are therefore suitable for representing things like currencies. Databases usually also provide a similar datatype, which Django's DecimalField maps to.

Greatly embarrassed, and thanks for clarifying. Will be more careful when answering next time :-)

Erik

Timothy W. Cook

unread,
Jan 8, 2014, 3:37:43 PM1/8/14
to django...@googlegroups.com
Well, Erik.  I appreciate you answering even if it wasn't 100% accurate.  

But to post the solution to the issue, just for completeness. 

Yes, Django does store the field contents as decimal.Decimal objects.  In your templates or if writing out to a file (as I need to do) you need to use the formatting option. 

Example using the previously used model field:

str('%.10g' % self.min_inclusive).strip()
  
This removes all non-significant zeros. So it gives me '0' for a zero.  
Message has been deleted

Mike Dewhirst

unread,
Jan 8, 2014, 10:31:43 PM1/8/14
to django...@googlegroups.com


On Thursday, January 9, 2014 7:37:43 AM UTC+11, Timothy W. Cook wrote:

On Wed, Jan 8, 2014 at 6:07 PM, Erik Cederstrand <erik+...@cederstrand.dk> wrote:
Den 08/01/2014 kl. 17.56 skrev Daniel Roseman <dan...@roseman.org.uk>:
<snip> 
>
But to post the solution to the issue, just for completeness. 

Yes, Django does store the field contents as decimal.Decimal objects.  In your templates or if writing out to a file (as I need to do) you need to use the formatting option. 

Example using the previously used model field:

str('%.10g' % self.min_inclusive).strip()
  
This removes all non-significant zeros. So it gives me '0' for a zero.  

I use a slightly different approach to chop unwanted zeroes ...

def chop_zeros(val):
    if isinstance(val, decimal.Decimal):
        return float(val)
    return val

... which I call for *all* numeric values before I do any string formatting. Which is why it works for me.

Mike

Timothy W. Cook

unread,
Jan 9, 2014, 3:37:38 AM1/9/14
to django...@googlegroups.com

On Wed, Jan 8, 2014 at 10:42 PM, Dennis Lee Bieber <wlf...@ix.netcom.com> wrote:
 
        If Django's "DecimalField" is NOT use Python's Decimal type, I'd be
concerned... Python's Decimal is NOT a "float".

        However, the conversion of a Decimal to/from PostgreSQL might result in
a floating point value -- which I'd consider a flaw in the database adapter
as PostgreSQL does have a NUMERIC data type that should map directly to
Python Decimal.
--

It does use decimal.Decimal and it does map to PostgreSQL numeric.   The representation via the ORM though ends up being in scientific number format in the admin interface.  This is what caused my concern.  I expected a visually decimal number; a 0  or as PostgreSQL/PGAdmin displays it, 0.0000000000. 
   

 

Eric Rouleau

unread,
Jan 14, 2014, 2:23:17 AM1/14/14
to django...@googlegroups.com
The problem seems to be in the postgres backend or Psycopg 2.5.2 adapter... I have the same problem and the data in postgres is 0.00000000 but when fetched by django it comes up as Decimal("0E-8") (with shell access not only admin), if I switch to sqlite3 backend then it works perfectly

Tom Evans

unread,
Jan 14, 2014, 9:24:30 AM1/14/14
to django...@googlegroups.com
On Tue, Jan 14, 2014 at 7:23 AM, Eric Rouleau <xbl...@gmail.com> wrote:
> The problem seems to be in the postgres backend or Psycopg 2.5.2 adapter...
> I have the same problem and the data in postgres is 0.00000000 but when
> fetched by django it comes up as Decimal("0E-8") (with shell access not only
> admin), if I switch to sqlite3 backend then it works perfectly
>

Decimal("0E-8") == Decimal(0) == Decimal(0.0)

If you do not want the python representation of your field to be a
Decimal, do not use DecimalField, use FloatField.

https://docs.djangoproject.com/en/1.5/ref/models/fields/#floatfield-vs-decimalfield

http://docs.python.org/2.7/library/decimal.html#module-decimal

Cheers

Tom
Reply all
Reply to author
Forward
0 new messages