2017-08-18 7 views
2

浮動小数点をサポートするために除算演算子を更新する前の作業では、datetime.timedeltaを拡張しました(python 3.xより前にはサポートされていません)。私のモデルの1つでDurationFieldを使い始めたのですが、私の拡張timedeltaクラスを使ったカスタムバージョンを作成して、クエリの後に返されるオブジェクトに自分のカスタムtimedeltaクラスが含まれるようにしたいと思います。これを実装する正しいアプローチは何ですか?Djangoモデルフィールド内のサブクラス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

+0

私は残念ながら知らない、私はどのようにすべてのフックを理解するのに苦労してきました一緒に、私の編集は本質的に疑似推測作業に基づいています!期間フィールドクラスの私の唯一の編集は 'TimeDeltaExtended'を追加することです – n0rman0

答えて

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) 
+0

ありがとう、理想的(とエレガント)です。これは私のためにあなたの例として使用されて動作します。しかし、 'MyDurationField'を含むモデルのクエリを実行すると、' to_python'以外の別の関数が使用されているため、フィールドは通常のtimedeltaで表されます。 – n0rman0

+1

また、dbから返された値をpythonオブジェクトに変換するメソッドである 'from_db_value()'を定義する必要があります。 'to_python()'のようにすることができます:最初に 'super'を呼び出してから、値を変換してください。 Docs [ここ](https://docs.djangoproject.com/en/1.11/howto/custom-model-fields/#converting-values-to-python-objects)また、 'to_python'メソッドで' value'がすでに 'TimeDeltaExtended'インスタンスであるケースを追加するべきです。 – dirkgroten

関連する問題