【问题标题】:Subclass timedelta within Django model fieldDjango模型字段中的子类timedelta
【发布时间】:2017-08-18 14:36:13
【问题描述】:

我已经扩展了datetime.timedelta 之前的一些工作,以更新除法运算符以支持浮点数(在 python 3.x 之前不支持)。在我的一个模型中开始使用 DurationField 之后,我想创建一个自定义版本,它使用我的扩展 timedelta 类,以便查询后返回的对象包括我的自定义 timedelta 类。实现这一点的正确方法是什么?

我一直在编辑DurationField 类本身,同时我想知道如何执行上述操作,然后再进行下一步以了解如何添加自定义模型字段。代码如下(modified Django source code:

class TimeDeltaExtended(datetime.timedelta):
    def __div__(self, divisor):
        return TimeDeltaExtended(seconds=self.total_seconds()/divisor)

    def __mul__(self, multiplier):
        return TimeDeltaExtended(seconds=self.total_seconds()*multiplier)

    def __add__(self, other):
        if isinstance(other, int) and other is 0:
            return self
        else:
            datetime.timedelta.__add__(other)

class DurationField(Field):
...

    def to_python(self, value):
        if value is None:
            return value
        if isinstance(value, TimeDeltaExtended):
            return value
        try:
            parsed = parse_duration(value)
        except ValueError:
            pass
        else:
            if parsed is not None:
                return parsed

        raise exceptions.ValidationError(
            self.error_messages['invalid'],
            code='invalid',
            params={'value': value},
        )
...

但是,当我使用此代码查询时,仍会返回正常的 TimeDelta 对象。这甚至是我应该关注的区域吗?

环境 Python 2.7、Django 1.11

【问题讨论】:

  • 不幸的是,我不知道,我一直在努力理解这一切是如何联系在一起的,我的编辑基本上是基于虚假的猜测工作!我对 durationfield 类的唯一编辑是添加 TimeDeltaExtended

标签: python django


【解决方案1】:

这就是持续时间字段将如何解析timedelta(seconds=123.456)的序列化形式:

>>> DurationField().to_python('00:02:03.456000')
datetime.timedelta(0, 123, 456000)

您可以让超类完成繁重的验证、异常处理等工作。只需转换为您的专用类作为后处理步骤:

>>> class MyDurationField(DurationField):
...     def to_python(self, value):
...         timedelta = super(MyDurationField, self).to_python(value)
...         return TimeDeltaExtended(seconds=timedelta.total_seconds())
...     
>>> MyDurationField().to_python('00:02:03.456000')
TimeDeltaExtended(0, 123, 456000)
>>> MyDurationField().to_python('00:02:03.456000') / 2.0
TimeDeltaExtended(0, 61, 728000)

【讨论】:

  • 谢谢,看起来很理想(而且优雅)。当用作您的示例时,这对我有用。但是,当我对包含 MyDurationField 的模型运行查询时,该字段仍由正常的 timedelta 表示,可能是因为使用了 to_python 以外的其他函数?
  • 您还需要定义from_db_value(),它是将db返回的值转换为python对象的方法。你应该可以像to_python() 那样做:首先调用super,然后转换值。文档here。另请注意,您应该在 to_python 方法中添加 case value 已经是 TimeDeltaExtended 实例。
猜你喜欢
  • 2013-02-03
  • 2011-06-23
  • 1970-01-01
  • 1970-01-01
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
相关资源
最近更新 更多