#34260: models.FloatField documentation doesn't mention that +inf, -inf, and NaN
are invalid.
-------------------------------------+-------------------------------------
     Reporter:  Matt Cooper          |                    Owner:  nobody
         Type:                       |                   Status:  new
  Cleanup/optimization               |
    Component:  Documentation        |                  Version:  4.1
     Severity:  Normal               |               Resolution:
     Keywords:  floatfield           |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  1                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by Matt Cooper):

 * status:  closed => new
 * resolution:  invalid =>


Comment:

 Ah, I made two mistakes in my research, covered below.

 I believe a scoped-down version of this proposed change is valid, because
 `float('nan')` is considered "null" (at least on SQLite). This is not
 obvious, and much like the "empty string vs null" discussion in CharField,
 would have helped me. The infinities do seem to work properly, so as
 mentioned above, this must be database-dependent.

 In that test case, is the field `null=True`? In a brand new Django 4.1
 project with the following `models.py` pointing to a SQLite database:

 {{{#!python
 from django.db import models

 class Example(models.Model):
     nullable_float = models.FloatField(null=True)
     nonnullable_float = models.FloatField()
 }}}

 then I get the following in `./manage.py shell`:

 {{{#!python
 >>> from repro.models import Example
 >>> e1 = Example(nullable_float=1.0, nonnullable_float=2.0)
 >>> e2 = Example(nullable_float=float('nan'), nonnullable_float=2.0)
 >>> e3 = Example(nullable_float=1.0, nonnullable_float=float('nan'))
 >>> e1.save()
 >>> e2.save()
 >>> e3.save()
 Traceback (most recent call last):
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-
 packages/django/db/backends/utils.py", line 89, in _execute
     return self.cursor.execute(sql, params)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-
 packages/django/db/backends/sqlite3/base.py", line 357, in execute
     return Database.Cursor.execute(self, query, params)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 sqlite3.IntegrityError: NOT NULL constraint failed:
 repro_example.nonnullable_float

 The above exception was the direct cause of the following exception:

 Traceback (most recent call last):
   File "<console>", line 1, in <module>
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-packages/django/db/models/base.py",
 line 812, in save
     self.save_base(
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-packages/django/db/models/base.py",
 line 863, in save_base
     updated = self._save_table(
               ^^^^^^^^^^^^^^^^^
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-packages/django/db/models/base.py",
 line 1006, in _save_table
     results = self._do_insert(
               ^^^^^^^^^^^^^^^^
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-packages/django/db/models/base.py",
 line 1047, in _do_insert
     return manager._insert(
            ^^^^^^^^^^^^^^^^
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-
 packages/django/db/models/manager.py", line 85, in manager_method
     return getattr(self.get_queryset(), name)(*args, **kwargs)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-packages/django/db/models/query.py",
 line 1791, in _insert
     return query.get_compiler(using=using).execute_sql(returning_fields)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-
 packages/django/db/models/sql/compiler.py", line 1660, in execute_sql
     cursor.execute(sql, params)
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-
 packages/django/db/backends/utils.py", line 103, in execute
     return super().execute(sql, params)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-
 packages/django/db/backends/utils.py", line 67, in execute
     return self._execute_with_wrappers(
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-
 packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
     return executor(sql, params, many, context)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-
 packages/django/db/backends/utils.py", line 84, in _execute
     with self.db.wrap_database_errors:
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-packages/django/db/utils.py", line
 91, in __exit__
     raise dj_exc_value.with_traceback(traceback) from exc_value
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-
 packages/django/db/backends/utils.py", line 89, in _execute
     return self.cursor.execute(sql, params)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "/Users/vtbassmatt/Library/Caches/pypoetry/virtualenvs/django34260
 -KHbD0UBT-py3.11/lib/python3.11/site-
 packages/django/db/backends/sqlite3/base.py", line 357, in execute
     return Database.Cursor.execute(self, query, params)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 django.db.utils.IntegrityError: NOT NULL constraint failed:
 repro_example.nonnullable_float
 }}}

 And for completeness, my mistakes:
 1. I was looking at the `FloatField` code for forms, not models, because I
 searched `FloatField` and didn't pay close enough attention. See
 
https://github.com/django/django/blob/0fbdb9784da915fce5dcc1fe82bac9b4785749e5/django/forms/fields.py#L370.
 2. I had only tested `float('nan')` myself. Once I made the above search
 error, I assumed that `float('inf')` would behave identically, but didn't
 test it since I wanted to get back to my task at hand.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34260#comment:4>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/01070185ba8bdb81-0fed819d-eaca-4552-bc50-7b0e76608520-000000%40eu-central-1.amazonses.com.

Reply via email to