Djangoの場合1.1。
これはmodels.pyにあります。
class User(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
行を更新すると、次のようになります。
[Sun Nov 15 02:18:12 2009] [error] /home/ptarjan/projects/Twitter-meme/Django/db/backends/mysql/base.py:84: Warning: Column 'created' cannot be null
[Sun Nov 15 02:18:12 2009] [error] return self.cursor.execute(query, args)
私のデータベースの関連部分は次のとおりです。
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
これは心配の原因ですか。
副次的な質問:私の管理ツールでは、これら2つのフィールドは表示されません。それは予想されますか?
auto_now
属性が設定されているフィールドもeditable=False
を継承するため、管理パネルには表示されません。 auto_now
と auto_now_add
引数をなくすことについては過去に話がありました、そしてそれらはまだ存在していますが、 custom save()
メソッド を使うほうが得策だと思います。
そのため、これを正しく機能させるには、auto_now
またはauto_now_add
を使用せず、created
が設定されていない場合にのみid
が更新されるように独自のsave()
メソッドを定義することをお勧めします。アイテムが保存されるたびにmodified
を更新します。
私がDjangoを使って書いた他のプロジェクトでもまったく同じことをしたので、あなたのsave()
はこのようになるでしょう:
from Django.utils import timezone
class User(models.Model):
created = models.DateTimeField(editable=False)
modified = models.DateTimeField()
def save(self, *args, **kwargs):
''' On save, update timestamps '''
if not self.id:
self.created = timezone.now()
self.modified = timezone.now()
return super(User, self).save(*args, **kwargs)
お役に立てれば!
コメントに応えて編集:
これらのフィールド引数に頼るのではなく、save()
のオーバーロードに固執する理由は2つあります。
datetime.datetime
に応じてTZ対応オブジェクトまたは単純なsettings.USE_TZ
オブジェクトが返されるため、Django.utils.timezone.now()
vs. datetime.datetime.now()
を使用してください。なぜOPでエラーが発生したのかを説明するために、私は正確にはわかりませんが、auto_now_add=True
があってもcreated
はまったく入力されていないようです。私にはそれはバグとして際立っており、上の私の小さなリストの項目#1を強調しています:auto_now
とauto_now_add
はせいぜい薄片です。
しかし、私は 受け入れられた答え で表された意見がやや時代遅れであることを指摘したいと思いました。最近の議論によると(Djangoのバグ #7634 と #12785 ) auto_nowとauto_now_addはどこにも行きません。 最初のディスカッション に進んでも、(DRYのように)RYに対する強い議論が見つかるでしょう。 )カスタム保存方法で。
より良い解決策(カスタムフィールドタイプ)が提供されていますが、Djangoにするための十分な推進力はありませんでした。あなたは3行であなた自身のものを書くことができます(それは Jacob Kaplan-Mossの提案 です)。
from Django.db import models
from Django.utils import timezone
class AutoDateTimeField(models.DateTimeField):
def pre_save(self, model_instance, add):
return timezone.now()
#usage
created_at = models.DateField(default=timezone.now)
updated_at = models.AutoDateTimeField(default=timezone.now)
副次的な質問について言えば、あなたがadminでこのフィールドを見たければ(しかし、あなたはそれを編集することができないでしょう)、あなたはあなたのadminクラスにreadonly_fields
を加えることができます。
class SomeAdmin(ModelAdmin):
readonly_fields = ("created","modified",)
まあ、これは最新のDjangoバージョンにのみ当てはまります(私は、1.3以上を信じています)
ここで最も簡単な(そしておそらく最もエレガントな)解決策は、default
name__をcallableに設定できるという事実を活用することです。そのため、adminの特別なauto_now処理を回避するには、次のようにフィールドを宣言するだけです。
from Django.utils import timezone
date_filed = models.DateField(default=timezone.now)
デフォルト値が更新されないため、timezone.now()
を使用しないことが重要です(つまり、デフォルトはコードがロードされたときにのみ設定されます)。自分でこれをたくさんやっていると感じたら、カスタムフィールドを作成することができます。しかし、これはすてきなDRYです。
モデルクラスをこのように変更したとします。
class MyModel(models.Model):
time = models.DateTimeField(auto_now_add=True)
time.editable = True
それからこのフィールドは私の管理者変更ページに表示されます
これまでに読んだこととこれまでにDjangoで経験したことに基づいて、auto_now_addはバグがあります。私はjthanismに同意します---通常のsaveメソッドを上書きします。それでは、乾燥させるために、TimeStampedという抽象モデルを作成します。
from Django.utils import timezone
class TimeStamped(models.Model):
creation_date = models.DateTimeField(editable=False)
last_modified = models.DateTimeField(editable=False)
def save(self, *args, **kwargs):
if not self.creation_date:
self.creation_date = timezone.now()
self.last_modified = timezone.now()
return super(TimeStamped, self).save(*args, **kwargs)
class Meta:
abstract = True
そして、このタイムスタンプ付きの振る舞いを持つモデルが欲しいときは、ただサブクラスにしてください:
MyNewTimeStampyModel(TimeStamped):
field1 = ...
フィールドをadminに表示したい場合は、editable=False
オプションを削除してください。
これは心配の原因ですか。
いいえ、Djangoはモデルを保存している間自動的にそれを追加しますので、それは期待されています。
副次的な質問:私の管理ツールでは、これら2つのフィールドは表示されません。それは予想されますか?
これらのフィールドは自動追加されるため、表示されません。
上記に加えて、synackが言ったように、これを削除することがDjangoメーリングリストで議論されています。
私の各モデルにカスタムのsave()を書くのは、auto_nowを使うよりはるかに面倒です。
明らかに、すべてのモデルにそれを書く必要はありません。あなたはそれを一つのモデルに書いてそれから他のものを継承することができます。
しかし、auto_add
とauto_now_add
があるので、私は自分でメソッドを書くのではなくそれらを使うことにしました。
Createdにtimezone.now()
を、modifiedにauto_now
を使うことができます。
from Django.utils import timezone
class User(models.Model):
created = models.DateTimeField(default=timezone.now())
modified = models.DateTimeField(auto_now=True)
デフォルトのauto- increment int
の代わりにカスタムの主キーを使用している場合、auto_now_add
はバグの原因となります。
これがDjangoのデフォルトのコード DateTimeField.pre_save withauto_now
とauto_now_add
です。
def pre_save(self, model_instance, add):
if self.auto_now or (self.auto_now_add and add):
value = timezone.now()
setattr(model_instance, self.attname, value)
return value
else:
return super(DateTimeField, self).pre_save(model_instance, add)
add
というパラメータが何であるかわかりません。私はそれがいくつかのようになることを願っています:
add = True if getattr(model_instance, 'id') else False
新しいレコードはattr
id
を持たないので、getattr(model_instance, 'id')
はFalseを返し、フィールドに値を設定しないことになります。
管理画面については、 この答え を参照してください。
注:auto_now
およびauto_now_add
はデフォルトでeditable=False
に設定されているため、これが適用されます。
今日は仕事で似たようなものが必要でした。デフォルト値はtimezone.now()
ですが、FormMixin
から継承する管理ビューとクラスビューの両方で編集できるため、models.py
で作成された場合、次のコードがこれらの要件を満たしました。
from __future__ import unicode_literals
import datetime
from Django.db import models
from Django.utils.functional import lazy
from Django.utils.timezone import localtime, now
def get_timezone_aware_now_date():
return localtime(now()).date()
class TestDate(models.Model):
created = models.DateField(default=lazy(
get_timezone_aware_now_date, datetime.date)()
)
DateTimeField
の場合、.date()
を関数から削除し、datetime.date
をdatetime.datetime
またはそれ以上のtimezone.datetime
に変更すると思います。 DateTime
で試していないが、Date
でのみ試してみた。
auto_now=True
はDjango 1.4.1ではうまくいきませんでしたが、以下のコードは私を救いました。タイムゾーンを意識した日時です。
from Django.utils.timezone import get_current_timezone
from datetime import datetime
class EntryVote(models.Model):
voted_on = models.DateTimeField(auto_now=True)
def save(self, *args, **kwargs):
self.voted_on = datetime.now().replace(tzinfo=get_current_timezone())
super(EntryVote, self).save(*args, **kwargs)