Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#30238 closed Bug (invalid)

Exception when saving model created with string for DateField

Reported by: Mitchell Harvey Owned by: nobody
Component: Database layer (models, ORM) Version: 2.1
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

If you instantiate a new model object with a keyword argument value for a DateField given a string, an exception is thrown when the object is saved. However, the model is saved anyways.

Example Error:
AttributeError: 'str' object has no attribute 'isoformat'

Call Stack:

File "REDACTED", line 746, in migrate_remote_unactive_driver
    local_driver.save()
  File "REDACTED", line 171, in save
    super(Driver, self).save(*args, **kwargs)
  File "REDACTED/env/lib/python3.6/site-packages/django/db/models/base.py", line 729, in save
    force_update=force_update, update_fields=update_fields)
  File "REDACTED/env/lib/python3.6/site-packages/django/db/models/base.py", line 769, in save_base
    update_fields=update_fields, raw=raw, using=using,
  File "REDACTED/env/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 178, in send
    for receiver in self._live_receivers(sender)
  File "REDACTED/env/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 178, in <listcomp>
    for receiver in self._live_receivers(sender)
  File "REDACTED", line 12, in create_launch_list
    serialized_obj = serializers.serialize('json', [instance])
  File "REDACTED/env/lib/python3.6/site-packages/django/core/serializers/__init__.py", line 128, in serialize
    s.serialize(queryset, **options)
  File "REDACTED/env/lib/python3.6/site-packages/django/core/serializers/base.py", line 89, in serialize
    self.handle_field(obj, field)
  File "REDACTED/env/lib/python3.6/site-packages/django/core/serializers/python.py", line 51, in handle_field
    self._current[field.name] = self._value_from_field(obj, field)
  File "REDACTED/env/lib/python3.6/site-packages/django/core/serializers/python.py", line 47, in _value_from_field
    return value if is_protected_type(value) else field.value_to_string(obj)
  File "REDACTED/env/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 1281, in value_to_string
    return '' if val is None else val.isoformat()
AttributeError: 'str' object has no attribute 'isoformat'

django/db/models/fields/init.py

value_to_string(self, obj)

Presumes that obj is not of type string already.

To Reproduce:

Create a model with a a field of type 'DateField'

class MyModel(models.Model):

   worthless_field = models.DateField(null=True, blank=True)

Instantiate and save an object of type 'MyModel' in a view.py:

my_model_args = { 'worthless_field' : '2019-02-07'}
myExceptionalModel = MyModel( **my_model_args)

# Exception thrown here
myExceptionalModel.save()

# Although, model is actually saved.

Please check if the value is a valid datetime string already before attempting to convert it to a string. It would be nice if a model was not saved when an exception is thrown.

Or do whatever you like, I have to work around it anyways.

Good luck, love Django, great job guys!

Attachments (1)

ticket_30238.zip (6.5 KB ) - added by Carlton Gibson 5 years ago.
Sample app with provided model and test case.

Download all attachments as: .zip

Change History (3)

by Carlton Gibson, 5 years ago

Attachment: ticket_30238.zip added

Sample app with provided model and test case.

comment:1 by Carlton Gibson, 5 years ago

Resolution: invalid
Status: newclosed

The AttributeError is not raised. This test fails at the assertRaisesMessage() call:

class Tests(TestCase):

    def test_attribute_error_stops_save(self):

        my_model_args = { 'worthless_field' : '2019-02-07'}
        myExceptionalModel = MyModel( **my_model_args)

        msg = "'str' object has no attribute 'isoformat'"
        with self.assertRaisesMessage(AttributeError, msg):
            myExceptionalModel.save()

        self.assertEqual(0, MyModel.objects.count())

Behaviour is as expected:

>>> myExceptionalModel.save()
>>> myExceptionalModel.refresh_from_db()
>>> myExceptionalModel.worthless_field
datetime.date(2019, 2, 7)

Sample app with model and test case attached.

Last edited 5 years ago by Carlton Gibson (previous) (diff)

comment:2 by Tim Graham, 5 years ago

Looking at the traceback in the ticket description, the crash comes from a signal handler, create_launch_list.

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