Djangoの日時の問題(default = datetime.now())


283

以下のdbモデルがあります:

from datetime import datetime    

class TermPayment(models.Model):
    # I have excluded fields that are irrelevant to the question
    date = models.DateTimeField(default=datetime.now(), blank=True)

以下を使用して新しいインスタンスを追加します。

tp = TermPayment.objects.create(**kwargs)

私の問題:データベースのすべてのレコードの日付フィールドの値が同じです。これは最初の支払いの日付です。サーバーの再起動後、1つのレコードには新しい日付が含まれ、他のレコードには最初のレコードと同じ日付が含まれます。一部のデータがキャッシュされているように見えますが、どこにあるかわかりません。

データベース:mysql 5.1.25

ジャンゴv1.1.1


1
このような関数にデフォルト設定することは不可能ですか?:default=datetime.now- now()DateTimeFieldの標準ではないように呼び出すことなく、注意してください...しかし、便利です。
viridis

回答:


597

datetime.now()レコードが追加されるたびではなく、モデルが定義されたときに評価されているように見えます。

Djangoには、すでに実行しようとしていることを実行する機能があります。

date = models.DateTimeField(auto_now_add=True, blank=True)

または

date = models.DateTimeField(default=datetime.now, blank=True)

2番目の例と現在の例の違いは、括弧がないことです。渡すことによってdatetime.now、括弧なしで、あなたはレコードが追加されるたびに呼び出される実際の関数を、渡しています。これを渡すとdatetime.now()、関数を評価して戻り値を渡すだけになります。

詳細については、Djangoのモデルフィールドリファレンスをご覧ください。


206
重要な注意:auto_now_addを使用すると、管理者でフィールドを編集できなくなります
Jiaaro

7
すばらしい答え、ありがとう。datetime.nowをデフォルトとして、より複雑な式を表現する方法はありますか?たとえば、現在+ 30日(以下は機能しません) expiry = models.DateTimeField(default=datetime.now + timedelta(days=30))
michela

26
@michela datetime.nowは関数であり、関数にtimedeltaを追加しようとしています。のようなデフォルト値を設定するために独自のコールバックを定義してからdef now_plus_30(): return datetime.now() + timedelta(days = 30)、使用する必要がありますmodels.DateTimeField(default=now_plus_30)
Carson Myers

55
または、もちろん行うことができますdefault=lambda: datetime.now()+timedelta(days=30)
Michael Mior '19

34
注意して auto_now_addを使用していることはありません ..私は、これはすでに言われたことを知っているが、それは単に「管理」ページのメッターないフィールドは常に(編集不可)今と同じになりますので、デフォルトを使用するのと同じ
VAShhh

114

使用datetime.nowする代わりに、実際に使用する必要がありますfrom django.utils.timezone import now

参照:

次のようなものに行きます:

from django.utils.timezone import now


created_date = models.DateTimeField(default=now, editable=False)

13
これは非常に重要なメモです!datetime.nowを使用すると、タイムゾーンに対応していないローカルの日時を使用できます。後でそれを使用してタイムスタンプが付けられたフィールドauto_now_add(タイムゾーンを認識する)と比較すると、タイムゾーンの差が大きいため、間違った計算が行われる可能性があります。
イフタ2016

1
これは間違いなく非常に重要ですが、それ自体では実際に質問に答えることはできません。
チェコ語2017年


28

djangoモデルのデフォルトフィールドに関するドキュメントから:

フィールドのデフォルト値。これは、値または呼び出し可能なオブジェクトにすることができます。呼び出し可能の場合、新しいオブジェクトが作成されるたびに呼び出されます。

したがって、以下が機能するはずです。

date = models.DateTimeField(default=datetime.now,blank=True)

1
これはdjango 1.8以降でのみ可能です
David Schumann

@DavidNathanなぜですか?呼び出し可能なdefaultdjango-chinese-docs-14.readthedocs.io/en/latest/ref/models/…)の使用を含め、両方のオプションは1.4以前から存在していると思います
Mark

16

デビッドは正しい答えを持っていました。括弧()は、モデルが評価されるたびに呼び出し可能な timezone.now()が呼び出されるようにします。()をtimezone.now()(または単純なdatetimeオブジェクトを使用している場合はdatetime.now())から削除すると、次のようになります。

default=timezone.now

次に、期待どおりに動作します。
新しいオブジェクトは作成時に現在の日付を受け取りますが、manage.py makemigrations / migrateを実行するたびに日付が上書きされることはありません。

私はこれに遭遇しました。デビッドに感謝します。


10

datetime.now()クラスが作成されたときに新しいレコードがデータベースに追加されていない場合は、評価されます。

必要なことを達成するには、このフィールドを次のように定義します。

date = models.DateTimeField(auto_now_add=True)

このようにして、dateフィールドは新しいレコードごとに現在の日付に設定されます。


6

これに対する答えは実際には間違っています。

値を自動入力します(auto_now / auto_now_addはデフォルトと同じではありません)。デフォルト値は、実際には新しいオブジェクトの場合にユーザーに表示されるものです。私が通常行うことは次のとおりです。

date = models.DateTimeField(default=datetime.now, editable=False,)

これを管理ページで表現しようとしている場合は、「read_only」としてリストし、フィールド名を参照していることを確認してください

read_only = 'date'

繰り返しますが、私のデフォルト値は通常編集可能ではないため、これを行っています。特に指定しない限り、管理ページは編集不可を無視します。ただし、デフォルト値の設定と、ここで重要なauto_addの実装には確かに違いがあります。テストしてみてください!


6

datetime.now()クラスがインスタンス化されるときに、1回評価されます。括弧を削除して、関数datetime.nowが返されてから評価されるようにしてください。私のにデフォルト値を設定することで同じ問題があり、ここにDateTimeField私の解決策を書きまし


5

Python言語リファレンスの「関数の定義」の下:

デフォルトのパラメーター値は、関数定義の実行時に評価されます。これは、関数が定義されたときに式が1回評価され、同じ「事前計算された」値が各呼び出しに使用されることを意味します。

幸いなことに、Djangoには、auto_now引数を使用して、必要な処理を実行する方法がありますDateTimeField

date = models.DateTimeField(auto_now=True)

DateTimeFieldについては、Djangoのドキュメントをご覧ください。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.