Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#13487 closed (worksforme)

django.db.backends.util.typecast_date fails with a ValueError with sqlite3

Reported by: will@… Owned by: nobody
Component: Database layer (models, ORM) Version: 1.2-alpha
Severity: Keywords: sqlite3
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

When trying to convert a NULL field, typecast_date fails because SQLite returns a string consisting of "NULL".
The extra error text is "invalid literal for int() with base 10: 'NULL'".

Change History (2)

comment:1 Changed 5 years ago by kmtracey

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to worksforme
  • Status changed from new to closed

I can't recreate this. Given this model:

class Volstat(models.Model):
    max_volume = models.IntegerField()
    used_volume = models.IntegerField()
    expire_date = models.DateField(blank=True, null=True)

    def __unicode__(self):
        return u'Expires %s, max = %s, used = %d' % (self.expire_date, self.max_volume, self.used_volume)

I can create a record with an empty expire_date and have no trouble reading that back from the DB:

kmt@lbox:~/software/web/playground$ python manage.py reset ttt

You have requested a database reset.
This will IRREVERSIBLY DESTROY any data for
the "ttt" application in the database "Playground".
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel: yes
kmt@lbox:~/software/web/playground$ python manage.py shell
Python 2.5.2 (r252:60911, Jan 20 2010, 23:16:55) 
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.conf import settings
>>> settings.DATABASE_ENGINE
'sqlite3'
>>> import django
>>> django.get_version()
u'1.2 rc 1 SVN-13117'
>>> from ttt.models import Volstat
>>> Volstat.objects.create(max_volume=1, used_volume=1, expire_date=None)
<Volstat: Expires None, max = 1, used = 1>
>>> v = Volstat.objects.get(pk=1)
>>> v.expire_date
>>>

I had put a breakpoint in at typecast_date; it did not even get hit when None was specified as expire_date. It does get hit on reading from the DB if I specify expire_date as a string (or datetime.date object):

>>> Volstat.objects.create(max_volume=1, used_volume=1, expire_date='2008-01-01')
<Volstat: Expires 2008-01-01, max = 1, used = 1>
>>> v = Volstat.objects.get(pk=2)
> /home/kmt/django/trunk/django/db/backends/util.py(50)typecast_date()
-> return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null
(Pdb) print s
2008-01-01
(Pdb) c
>>> v.expire_date
datetime.date(2008, 1, 1)

I'm not sure how you have gotten the string "NULL" in for a date, since when I try that I get an error:

>>> Volstat.objects.create(max_volume=1, used_volume=1, expire_date='NULL')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/kmt/django/trunk/django/db/models/manager.py", line 138, in create
    return self.get_query_set().create(**kwargs)
  File "/home/kmt/django/trunk/django/db/models/query.py", line 352, in create
    obj.save(force_insert=True, using=self.db)
  File "/home/kmt/django/trunk/django/db/models/base.py", line 435, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)
  File "/home/kmt/django/trunk/django/db/models/base.py", line 518, in save_base
    for f in meta.local_fields if not isinstance(f, AutoField)]
  File "/home/kmt/django/trunk/django/db/models/fields/subclassing.py", line 28, in inner
    return func(*args, **kwargs)
  File "/home/kmt/django/trunk/django/db/models/fields/subclassing.py", line 28, in inner
    return func(*args, **kwargs)
  File "/home/kmt/django/trunk/django/db/models/fields/__init__.py", line 276, in get_db_prep_save
    return self.get_db_prep_value(value, connection=connection, prepared=False)
  File "/home/kmt/django/trunk/django/db/models/fields/subclassing.py", line 53, in inner
    return func(*args, **kwargs)
  File "/home/kmt/django/trunk/django/db/models/fields/__init__.py", line 649, in get_db_prep_value
    value = self.get_prep_value(value)
  File "/home/kmt/django/trunk/django/db/models/fields/__init__.py", line 644, in get_prep_value
    return self.to_python(value)
  File "/home/kmt/django/trunk/django/db/models/fields/__init__.py", line 608, in to_python
    raise exceptions.ValidationError(self.error_messages['invalid'])
ValidationError: [u'Enter a valid date in YYYY-MM-DD format.']

I get the same error trying this on the 1.1.X branch, so this is not new behavior.

How are you creating dates with the string value "NULL"?

comment:2 Changed 5 years ago by anonymous

Thanks for taking a look into this for me. It would appear that a curious combination of the setup I was using was at fault.
I populated a table with rows from a CSV file, and, because SQLite is dynamically typed, it didn't balk at assigning "NULL" as a string to a datetime field.

Note: See TracTickets for help on using tickets.
Back to Top