Adam Starrh
Adam Starrh

Reputation: 6968

Python/Django - String not accepted ('Expected a string or bytes-like object)

At the end of a form wizard, I have a custom save for an object:

def done(self, form_list, **kwargs):

    (...)

    start = datetime.strptime(self.request.session['event_start'], '%Y-%m-%d %H:%M:%S')
    duration = datetime.strptime(self.request.session['duration'], '%H:%M:%S').time()

    EventInstance.objects.create(
        event=event_obj,
        start=start,
        duration=duration,
        recurring='0F',
    )

    (...)

I've manually written a string in for the final step, to try and isolate the problem. When I try to run the final script, the traceback highlights the recurring field with a TypeError and tells me that Python expected string or bytes-like object.

This is my model:

class EventInstance(models.Model):
    event = models.ForeignKey(Event)
    start = models.DateTimeField()
    duration = models.DateTimeField()
    recurring = models.CharField(max_length=2)

event_obj is an Event object that I created earlier in the process. Can someone help me understand this error?

Traceback here:

Traceback:
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\core\handlers\base.py" in get_response
  132.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\views\generic\base.py" in view
  71.             return self.dispatch(request, *args, **kwargs)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\formtools\wizard\views.py" in dispatch
  237.         response = super(WizardView, self).dispatch(request, *args, **kwargs)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\views\generic\base.py" in dispatch
  89.         return handler(request, *args, **kwargs)
File "C:\Users\Zeratul\Documents\otherlane\Otherlane\Events\views.py" in post
  181.                 return self.render_done(form, **kwargs)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\formtools\wizard\views.py" in render_done
  357.                                   **kwargs)
File "C:\Users\Zeratul\Documents\otherlane\Otherlane\Events\views.py" in done
  239.             recurring='0F',
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\manager.py" in manager_method
  127.                 return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\query.py" in create
  348.         obj.save(force_insert=True, using=self.db)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\base.py" in save
  734.                        force_update=force_update, update_fields=update_fields)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\base.py" in save_base
  762.             updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\base.py" in _save_table
  846.             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\base.py" in _do_insert
  885.                                using=using, raw=raw)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\manager.py" in manager_method
  127.                 return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\query.py" in _insert
  920.         return query.get_compiler(using=using).execute_sql(return_id)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql
  973.             for sql, params in self.as_sql():
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\sql\compiler.py" in as_sql
  931.                 for obj in self.query.objs
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\sql\compiler.py" in <listcomp>
  931.                 for obj in self.query.objs
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\sql\compiler.py" in <listcomp>
  929.                     ) for f in fields
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\fields\__init__.py" in get_db_prep_save
  710.                                       prepared=False)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\fields\__init__.py" in get_db_prep_value
  1482.             value = self.get_prep_value(value)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\fields\__init__.py" in get_prep_value
  1461.         value = super(DateTimeField, self).get_prep_value(value)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\fields\__init__.py" in get_prep_value
  1317.         return self.to_python(value)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\db\models\fields\__init__.py" in to_python
  1420.             parsed = parse_datetime(value)
File "C:\Users\Zeratul\Envs\otherlane\lib\site-packages\django\utils\dateparse.py" in parse_datetime
  93.     match = datetime_re.match(value)

Exception Type: TypeError at /events/post_event/
Exception Value: expected string or bytes-like object

EDIT

Looking more closely at the traceback, it seems to be an issue with the "Duration" field. Perhaps because I am trying to save a time as a datetime object?

▼ Local vars
Variable    Value
__class__   <class 'django.db.models.fields.DateField'>
value   datetime.time(0, 30)
self    <django.db.models.fields.DateTimeField: duration>

Upvotes: 2

Views: 594

Answers (1)

Shang Wang
Shang Wang

Reputation: 25559

It's highlighted on the last line, but it's obvious that by tracing the stack it ends up in django's dateparse.py file, which indicates that it's related to datetime issues not correctly parsed. Traceback would only highlight a complete statement but since your create function is a multi-line statement, it marks on the recurring='0F' line. In other words, it tells you that your statement EventInstance.objects.create(......) is problematic.

I believe that your duration field is DateTimeField, but your duration variable is a datetime.time object. You can't feed a time object to datetime field obviously.

The solution is easy, change duration field to TimeField.

Django doc about TimeField.

Upvotes: 3

Related Questions