【问题标题】:Django & SQLite: DurationField arithmeticsDjango 和 SQLite:DurationField 算术
【发布时间】:2019-08-18 14:11:26
【问题描述】:

我有以下型号

class MyModel(models.Model):
    start = models.TimeField()
    finish = models.TimeField()
    penalty = models.IntegerField(blank=True, default=0)  # penalty in minutes

以及管理员中的以下查询集注释

def get_queryset(self, request):
    qs = super().get_queryset(request)
    qs = qs.annotate(
        total_time=ExpressionWrapper(
            F("finish") - F("start") + F("penalty") * 60,
            output_field=DurationField()
        )
    )
    return qs

当我检查 penalty != 0 所在行的注释值时,我得到类似 datetime.timedelta(0, 1800, 1800) 的信息(在这种情况下,罚款是 30 分钟)。
但是,我期望像datetime.timedelta(0, 3600) 这样的时间增量。有人可以解释一下吗?


我也试过

def get_queryset(self, request):
    qs = super().get_queryset(request)
    qs = qs.annotate(
        duration=ExpressionWrapper(
            F("finish") - F("start"),
            output_field=DurationField()
        )
    )
    qs = qs.annotate(
        total_time=ExpressionWrapper(
            F("duration") + F("route_shortening_penalty") * 60,
            output_field=DurationField()
        )
    )
    return qs

甚至

def get_queryset(self, request):
    qs = super().get_queryset(request)
    qs = qs.annotate(
        duration=ExpressionWrapper(
            F("finish") - F("start"),
            output_field=DurationField()
        ),
        penalty_duration=ExpressionWrapper(
            F("penalty") * 60,
            output_field=DurationField()
        )
    )
    qs = qs.annotate(
        total_time=ExpressionWrapper(
            F("duration") + F("penalty_duration"),
            output_field=DurationField()
        )
    )
    return qs

两者都导致

Traceback (most recent call last):
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/core/handlers/base.py", line 124, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/contrib/admin/options.py", line 604, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/utils/decorators.py", line 142, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/contrib/admin/sites.py", line 223, in inner
    return view(request, *args, **kwargs)
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/utils/decorators.py", line 45, in _wrapper
    return bound_method(*args, **kwargs)
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/utils/decorators.py", line 142, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/contrib/admin/options.py", line 1793, in changelist_view
    'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/db/models/query.py", line 250, in __len__
    self._fetch_all()
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/db/models/query.py", line 1186, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/db/models/query.py", line 63, in __iter__
    for row in compiler.results_iter(results):
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1009, in apply_converters
    value = converter(value, expression, connection)
  File "/home/dm/.virtualenvs/test/lib/python3.6/site-packages/django/db/backends/base/operations.py", line 573, in convert_durationfield_value
    return datetime.timedelta(0, 0, value)
TypeError: unsupported type for timedelta microseconds component: str

我正在使用Python 3.6.7Django==2.1.7SQLite version 3022000

【问题讨论】:

  • 如果惩罚是 DurationField 而不是 IntegerField 不是更有意义吗?
  • @JohnGordon 也尝试过,请参阅更新后的问题。
  • 为什么不用类属性代替注解?
  • @Pedro 因为无法对属性的 changelist_view 进行排序。我想根据注释结果排序。
  • 我没有看到任何代码表明您尝试了不同的模型定义。我只看到get_queryset() 的更改。

标签: python django sqlite duration timedelta


【解决方案1】:

如果你得到datetime.timedelta(0, 1800, 1800) 而不是正确的datetime.timedelta(0, 3600),那么你显然就快到了。

我假设 1800 秒是 F("finish")F("start") 之间的差异,而 1800 微秒来自 F("penalty") * 60

乘以60*1000*1000 而不是60penalty 从分钟转换为微秒:

total_time=ExpressionWrapper(
    F("finish") - F("start") + F("penalty") * 60000000,
    output_field=DurationField()
)

【讨论】:

  • 好的,所以有效的方法是乘以60000000(1 秒 = 1000000 微秒)。接受你指出我正确的方向,请相应地更新答案。
  • 谢谢。我应该先让我的孩子进行转换。
猜你喜欢
  • 1970-01-01
  • 2021-09-05
  • 2018-10-16
  • 2012-12-04
  • 2016-04-25
  • 2015-09-23
  • 2017-08-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多