为啥django-q会用箭头时间抛出异常

Posted

技术标签:

【中文标题】为啥django-q会用箭头时间抛出异常【英文标题】:Why does django-q throw exception with arrow time为什么django-q会用箭头时间抛出异常 【发布时间】:2021-07-29 13:50:18 【问题描述】:

我正在尝试创建一个 Django-q 计划并按照文档使用arrow 进行下一次运行我收到以下计划错误:

schedule(
        func='test.tasks.test_task',
        name='test_task_nightly',
        schedule_type=Schedule.DAILY,
        next_run=arrow.utcnow().replace(hour=23, minute=30),
        q_options='timeout': 10800, 'max_attempts': 1,
    )
Traceback (most recent call last):
  File "/usr/lib/python3.8/code.py", line 90, in runcode
    exec(code, self.locals)
  File "<console>", line 1, in <module>
    schedule(
  File "/home/user/PycharmProjects/app/venv/lib/python3.8/site-packages/django_q/tasks.py", line 122, in schedule
    s.full_clean()
  File "/home/user/PycharmProjects/app/venv/lib/python3.8/site-packages/django/db/models/base.py", line 1209, in full_clean
    self.clean_fields(exclude=exclude)
  File "/home/user/PycharmProjects/app/venv/lib/python3.8/site-packages/django/db/models/base.py", line 1251, in clean_fields
    setattr(self, f.attname, f.clean(raw_value, self))
  File "/home/user/PycharmProjects/app/venv/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 650, in clean
    value = self.to_python(value)
  File "/home/user/PycharmProjects/app/venv/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 1318, in to_python
    parsed = parse_datetime(value)
  File "/home/user/PycharmProjects/app/venv/lib/python3.8/site-packages/django/utils/dateparse.py", line 107, in parse_datetime
    match = datetime_re.match(value)
TypeError: expected string or bytes-like object

不确定为什么它不接受类似于 django-q 文档页面中给出的示例的时间格式。

编辑: 正在计划的任务:

def test_task():
    print('Executed test task')

没有什么太复杂的,只是为了测试目的

【问题讨论】:

【参考方案1】:

Django ORM(撰写本文时为 3.2 版)不接受任何 DateTimeField 中的 Arrow 对象。

Arrow 对象模拟 Python 的 datetime 对象接口,但它们不是真正的 datetime 对象。因此,如果接收到 Arrow 对象的任何代码都明确检查您的值是否是诚实的 datetime,它将失败。这正是代码中的内容 django.db.models.fields.DateTimeField.to_python 似乎在做:

def to_python(self, value):
    if value is None:
        return value
    if isinstance(value, datetime.datetime):
        return value
    if isinstance(value, datetime.date):
        value = datetime.datetime(value.year, value.month, value.day)
    ...
    try:
        parsed = parse_datetime(value)

如您所见,当它与datetimedate 实例不匹配时,Django 将其交给parse_datetime() 函数处理,该函数需要一个字符串。这解释了你的错误:TypeError: expected string or bytes-like object

您可以通过获取.datetime 属性来解决此问题,该属性将返回一个普通的旧python datetime,即

schedule(
        func='test.tasks.test_task',
        name='test_task_nightly',
        schedule_type=Schedule.DAILY,
        next_run=arrow.utcnow().replace(hour=23, minute=30).datetime,
        q_options='timeout': 10800, 'max_attempts': 1,
    )

【讨论】:

以上是关于为啥django-q会用箭头时间抛出异常的主要内容,如果未能解决你的问题,请参考以下文章

为啥不抛出异常的代码允许捕获已检查的异常?

为啥内部异常到达 ThreadException 处理程序而不是实际抛出的异常?

为啥尝试更改 _arr[3] 时没有抛出异常?

为啥geoip会抛出异常?

为啥不可能从 __toString() 抛出异常?

为啥抛出异常比返回错误代码更好?