celery / django-celery-beat

Celery Periodic Tasks backed by the Django ORM
Other
1.71k stars 433 forks source link

AttributeError at /admin/django_celery_beat/periodictask/1/change/: 'NoneType' object has no attribute 'strip' #278

Closed jmartens closed 3 years ago

jmartens commented 5 years ago

Summary:

Include a brief descrioption of the problem here, and fill out the version info below.

Django in a docker container connecting to a MySQL docker container running the following versions of celery and django-celery-beat:

>>> import celery
>>> print(celery.__version__)
4.3.0
>>> import django_celery_beat
>>> print(django_celery_beat.__version__)
1.5.0
>>> 

Exact steps to reproduce the issue:

  1. Create a simple periodic task w/o start date and time and save it, see below for record from DB
*************************** 1. row ***************************
             id: 1
           name: Test logging
           task: images.tasks.log
           args: []
         kwargs: {}
          queue: NULL
       exchange: NULL
    routing_key: NULL
        expires: NULL
        enabled: 1
    last_run_at: NULL
total_run_count: 0
   date_changed: 2019-08-04 07:49:45
    description: Testing my first Celery task, including logging
     crontab_id: NULL
    interval_id: 1
       solar_id: NULL
        one_off: 0
     start_time: NULL
       priority: NULL
        headers: {}
     clocked_id: NULL
1 row in set (0.000 sec)
  1. Update the task to have a start date (today) and start time (now) and save it

Detailed information

Please include more detailed information here, such as relevant information about your system setup, things you did to try and debug the problem, log messages, etc.

When updatign an existing periodic task in my DJango admin interface I received the following error:


Request Method: POST
Request URL: http://localhost:8000/admin/django_celery_beat/periodictask/1/change/

Django Version: 2.2.4
Python Version: 3.7.4
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django_celery_results',
 'django_celery_beat',
 'images']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']

Traceback:

File "/usr/local/lib/python3.7/site-packages/mysql/connector/connection_cext.py" in cmd_query
  472.                                raw_as_string=raw_as_string)

During handling of the above exception (Column 'total_run_count' cannot be null), another exception occurred:

File "/usr/local/lib/python3.7/site-packages/mysql/connector/django/base.py" in _execute_wrapper
  168.             return method(query, args)

File "/usr/local/lib/python3.7/site-packages/mysql/connector/cursor_cext.py" in execute
  266.                                          raw_as_string=self._raw_as_string)

File "/usr/local/lib/python3.7/site-packages/mysql/connector/connection_cext.py" in cmd_query
  475.                                              sqlstate=exc.sqlstate)

During handling of the above exception (1048 (23000): Column 'total_run_count' cannot be null), another exception occurred:

File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py" in execute
  99.             return super().execute(sql, params)

File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py" in execute
  67.         return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)

File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py" in _execute_with_wrappers
  76.         return executor(sql, params, many, context)

File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py" in _execute
  84.                 return self.cursor.execute(sql, params)

File "/usr/local/lib/python3.7/site-packages/mysql/connector/django/base.py" in execute
  218.         return self._execute_wrapper(self.cursor.execute, query, new_args)

File "/usr/local/lib/python3.7/site-packages/mysql/connector/django/base.py" in _execute_wrapper
  174.                         utils.IntegrityError(err.msg), sys.exc_info()[2])

File "/usr/local/lib/python3.7/site-packages/django/utils/six.py" in reraise
  683.             raise value.with_traceback(tb)

File "/usr/local/lib/python3.7/site-packages/mysql/connector/django/base.py" in _execute_wrapper
  168.             return method(query, args)

File "/usr/local/lib/python3.7/site-packages/mysql/connector/cursor_cext.py" in execute
  266.                                          raw_as_string=self._raw_as_string)

File "/usr/local/lib/python3.7/site-packages/mysql/connector/connection_cext.py" in cmd_query
  475.                                              sqlstate=exc.sqlstate)

During handling of the above exception (Column 'total_run_count' cannot be null), another exception occurred:

File "/usr/local/lib/python3.7/site-packages/mysql/connector/cursor_cext.py" in statement
  606.             return self._executed.strip().decode('utf8')

During handling of the above exception ('NoneType' object has no attribute 'strip'), another exception occurred:

File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
  115.                 response = self.process_exception_by_middleware(e, request)

File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py" in _get_response
  113.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py" in wrapper
  606.                 return self.admin_site.admin_view(view)(*args, **kwargs)

File "/usr/local/lib/python3.7/site-packages/django/utils/decorators.py" in _wrapped_view
  142.                     response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python3.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  44.         response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/sites.py" in inner
  223.             return view(request, *args, **kwargs)

File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py" in change_view
  1637.         return self.changeform_view(request, object_id, form_url, extra_context)

File "/usr/local/lib/python3.7/site-packages/django/utils/decorators.py" in _wrapper
  45.         return bound_method(*args, **kwargs)

File "/usr/local/lib/python3.7/site-packages/django/utils/decorators.py" in _wrapped_view
  142.                     response = view_func(request, *args, **kwargs)

File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py" in changeform_view
  1522.             return self._changeform_view(request, object_id, form_url, extra_context)

File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py" in _changeform_view
  1561.                 self.save_model(request, new_object, form, not add)

File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py" in save_model
  1088.         obj.save()

File "/usr/local/lib/python3.7/site-packages/django_celery_beat/models.py" in save
  548.         super(PeriodicTask, self).save(*args, **kwargs)

File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py" in save
  741.                        force_update=force_update, update_fields=update_fields)

File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py" in save_base
  779.                 force_update, using, update_fields,

File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py" in _save_table
  851.                                       forced_update)

File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py" in _do_update
  900.         return filtered._update(values) > 0

File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py" in _update
  760.         return query.get_compiler(self.db).execute_sql(CURSOR)

File "/usr/local/lib/python3.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
  1429.         cursor = super().execute_sql(result_type)

File "/usr/local/lib/python3.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
  1100.             cursor.execute(sql, params)

File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py" in execute
  103.             sql = self.db.ops.last_executed_query(self.cursor, sql, params)

File "/usr/local/lib/python3.7/site-packages/mysql/connector/django/operations.py" in last_executed_query
  127.         return force_text(cursor.statement, errors='replace')

File "/usr/local/lib/python3.7/site-packages/mysql/connector/django/base.py" in __getattr__
  230.         return getattr(self.cursor, attr)

File "/usr/local/lib/python3.7/site-packages/mysql/connector/cursor_cext.py" in statement
  608.             return self._executed.strip()

Exception Type: AttributeError at /admin/django_celery_beat/periodictask/1/change/
Exception Value: 'NoneType' object has no attribute 'strip'
jmartens commented 5 years ago

The exception causing this might actually be this:

During handling of the above exception (Column 'total_run_count' cannot be null)

As the originally reported Exception is triggered when handling the original exception

jmartens commented 5 years ago

The create statement does not allow NULL values:

MariaDB [blastfromthepast]> show create table django_celery_beat_periodictask\G
*************************** 1. row ***************************
       Table: django_celery_beat_periodictask
Create Table: CREATE TABLE `django_celery_beat_periodictask` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(200) NOT NULL,
  `task` varchar(200) NOT NULL,
  `args` longtext NOT NULL,
  `kwargs` longtext NOT NULL,
  `queue` varchar(200) DEFAULT NULL,
  `exchange` varchar(200) DEFAULT NULL,
  `routing_key` varchar(200) DEFAULT NULL,
  `expires` datetime DEFAULT NULL,
  `enabled` tinyint(1) NOT NULL,
  `last_run_at` datetime DEFAULT NULL,
  `total_run_count` int(10) unsigned NOT NULL,
  `date_changed` datetime NOT NULL,
  `description` longtext NOT NULL,
  `crontab_id` int(11) DEFAULT NULL,
  `interval_id` int(11) DEFAULT NULL,
  `solar_id` int(11) DEFAULT NULL,
  `one_off` tinyint(1) NOT NULL,
  `start_time` datetime DEFAULT NULL,
  `priority` int(10) unsigned DEFAULT NULL,
  `headers` longtext NOT NULL,
  `clocked_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`),
  KEY `django_celery_beat_periodictask_solar_id_a87ce72c` (`solar_id`),
  KEY `django_celery_beat_p_crontab_id_d3cba168_fk_django_ce` (`crontab_id`),
  KEY `django_celery_beat_p_interval_id_a8ca27da_fk_django_ce` (`interval_id`),
  KEY `django_celery_beat_periodictask_clocked_id_47a69f82` (`clocked_id`),
  CONSTRAINT `django_celery_beat_p_clocked_id_47a69f82_fk_django_ce` FOREIGN KEY (`clocked_id`) REFERENCES `django_celery_beat_clockedschedule` (`id`),
  CONSTRAINT `django_celery_beat_p_crontab_id_d3cba168_fk_django_ce` FOREIGN KEY (`crontab_id`) REFERENCES `django_celery_beat_crontabschedule` (`id`),
  CONSTRAINT `django_celery_beat_p_interval_id_a8ca27da_fk_django_ce` FOREIGN KEY (`interval_id`) REFERENCES `django_celery_beat_intervalschedule` (`id`),
  CONSTRAINT `django_celery_beat_p_solar_id_a87ce72c_fk_django_ce` FOREIGN KEY (`solar_id`) REFERENCES `django_celery_beat_solarschedule` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
1 row in set (0.001 sec)

The same request after a refresh completes after modifying the affected column like so:

MariaDB [blastfromthepast]> ALTER TABLE `django_celery_beat_periodictask` MODIFY COLUMN `total_run_count` int(10) unsigned
    -> ;
Query OK, 0 rows affected (0.160 sec)
Records: 0  Duplicates: 0  Warnings: 0
jmartens commented 5 years ago

Apparently the default is set to be 0, so I suspect that somewhere in the model or views this is set to None/NULL despite its editable attribute that is set to False