DjangoのDateTimeFieldの詳しい使い方: 日付と時刻を扱うフィールド
目次
- DjangoのDateTimeFieldの詳しい使い方
- DateTimeFieldの構造
- フィールドをDateTimeFieldで定義する
- デフォルト値を指定する
- auto_now_addとauto_now引数
- save()を改造して更新する
- dateフィルターで日付のフォーマットを指定する
- おわりに
DjangoのDateTimeFieldの詳しい使い方
Djangoのモデルにはいろいろなフィールドがあります。
CharField, TextField, BooleanFieldなどなど。
その中にDateTimeFieldという日付と時刻を扱うフィールドもあります。
このDateTimeFieldを使うと、Djangoのモデルに日付と時刻を記録することが出来ます。
この記事ではDjangoのDateTimeFieldについて詳しく解説します。
結論から言うとDateTimeFieldは↓のように使います。
from django.db import models class BlueArticle(models.Model): title = models.CharField(max_length=128, help_text='記事のタイトル') created = models.DateTimeField(help_text='作成日') # 記事の作成日を表現する
具体的にDateTimeFieldについて、↓の項目を見ていきたいと思います。
DateTimeFieldの構造
フィールドをDateTimeFieldで定義する
デフォルト値を指定する
auto_now_addとauto_now引数
save()を改造して更新する
dateフィルターで日付のフォーマットを指定する
関連記事
DjangoのChoiceFieldのわかりやすい使い方・書き方
DjangoのBooleanFieldの使い方: 真偽値, True, False
DateTimeFieldの構造
DjangoのDateTimeFieldは↓のような構造になっています。
class DateTimeField(auto_now=False, auto_now_add=False, **options)
DateTimeField | Model field reference | Django documentation | Django
DateTimeFieldはhelp_text
やdefault
などのDjangoのフィールドではお馴染みの引数もとります。
それに追加してauto_now
とauto_now_add
という引数も追加されています。
auto_now引数
auto_now
引数はデフォルトでFalse
です。
True
を指定すると、モデルのインスタンスが保存されるたびにこのDateTimeFiledのフィールドが更新されるようになります。
つまり、モデルのsave()
などを呼び出すと、そのたびにDateTimeFieldのフィールがその時の日付と時刻で自動で更新されます。
この引数はたとえばmodified
などのモデルの更新日を表すフィールドを作りたい場合に有効な引数と言えます。
手動でmodified
の値を更新しなくてもDjangoが自動で値を更新してくれるからです。
auto_now_add引数
auto_now_add
引数はデフォルトでFalse
です。
True
を指定するとモデルがDBに保存されたときに値が自動で保存されます。
つまりモデルがDBにINSERT
されときにです。
この引数はたとえばcreated
などのモデルの作成日を表すフィールドを作りたい時に有効な引数です。
DateTimeFieldのフィールドのauto_now_add
をTrue
にしておけば、そのモデルがDBに保存されたときにフィールドの値が自動で更新されます。
フィールドをDateTimeFieldで定義する
DateTimeFieldは他のフィールドと同様にモデルに定義することで使うことが出来ます。
たとえばブログの記事を表現するモデルBlueArticle
があったとして、そのモデルにDateTimeFieldを使ってフィールドcreated
を定義するには↓のようにします。
from django.db import models class BlueArticle(models.Model): title = models.CharField(max_length=128, help_text='記事のタイトル') created = models.DateTimeField(help_text='作成日') # 記事の作成日を表現する
↑の場合、created
というフィールドがDateTimeFieldで作成されたフィールドです。
↑はシンプルにhelp_text
引数だけを指定してあとは未指定のままです。
このモデルは↓のようなコードでインスタンスを作成することが出来ます。
from blog.models import BlueArticle from django.utils import timezone BlueArticle.objects.create( title='青い記事', created=timezone.now(), # 手動でDateTimeFieldを初期化 )
created
フィールドの初期化にはDjangoの便利ツールであるtimezone
を使っています。
timezone.now()
で現在時刻をcreated
に設定しています。
この定義で作成したモデルのインスタンスをテンプレートファイルに渡した場合、↓のように参照することが可能です。
<h1>{{ article.title }}</h1> <p>作成日: {{ article.created }}</p>
出力される画面は↓のようになります。
デフォルト値を指定する
DateTimeFieldの引数default
にデフォルト値を指定すると、そのフィールドのデフォルトの値を設定することが出来ます。
from django.db import models from django.utils import timezone class GreenArticle(models.Model): title = models.CharField(max_length=128, help_text='記事のタイトル') created = models.DateTimeField(default=timezone.now(), help_text='作成日')
↑の場合、created
のデフォルト値の設定には例によってDjangoのtimezone
を使っています。
↑のようにコードを書くと、コードが実行されたときのタイムゾーンの値がcreated
のデフォルト値になります。
つまり、このコードにはあまり信頼性がありません。
プロジェクトをPythonで実行した段階でデフォルト値がころころ変わるからです。
現在時刻ではなくモデルの作成日をcreated
などのフィールドのデフォルト値にしたい場合は、先述と後述するauto_now_add
引数を使うか、後述のようにsave()
を改造します。
この定義のモデルは↓のようにインスタンスを作成することができます。
created
にはデフォルト値が設定されているので外部からの値の指定は必要ありません。
from blog.models import GreenArticle GreenArticle.objects.create( title='緑色の記事', )
またこのモデルをテンプレートファイルで参照する場合は↓のようなコードになります。
<h1>{{ article.title }}</h1> <p>作成日: {{ article.created }}</p>
表示される画面は↓のようになります。
ちなみにこのようなデフォルト値の指定を行うと、Djangoから警告されます。
↓は警告内容です。
WARNINGS: blog.GreenArticle.created: (fields.W161) Fixed default value provided. HINT: It seems you set a fixed date / time / datetime value as default for this field. This may not be what you want. If you want to have the current date as default, use `django.utils.timezone.now`
意訳すると「デフォルト値が固定です。createdのデフォルト値に固定の日付を設定していますが、これは現在の日付をデフォルト値にするものではありません。現在の日付を設定したい場合はdjango.utils.timezone.now
を使ってください。」
(^ _ ^) | timezone使ってるやんけ |
と思われた方もいると思いますが、要はtimezone.now()
で生成しているオブジェクトが現在の日付を表現してないよ、Pythonがコードを実行したときの日付になっちゃうよ、ということです。
これを警告に従って変更するには↓のようなコードを書きます。
from django.db import models from django.utils import timezone class YellowArticle(models.Model): title = models.CharField(max_length=128, help_text='記事のタイトル') created = models.DateTimeField(default=timezone.now, help_text='作成日')
default=timezone.now()
のカッコが取れてdefault=timezone.now
になってます。
こうすればデフォルト値として現在の日付が使われます。
しかしこの方法もネットでは非推奨になっているという指摘が出てきます。
後述のsave()
の改造を参照してください。
auto_now_addとauto_now引数
auto_now_add
を有効にしたcreated
フィールドと、auto_now
を有効にしたmodified
フィールドを定義します。
from django.db import models class RedArticle(models.Model): title = models.CharField(max_length=128, help_text='記事のタイトル') created = models.DateTimeField(auto_now_add=True, help_text='作成日') modified = models.DateTimeField(auto_now=True, help_text='更新日')
先述の通り、auto_now_add
はモデルのインスタンスがDBに作成されるときに値が設定されます。
auto_now
はモデルが保存されるたびに値が更新されます。
この定義のモデルは↓のようにインスタンスを作成することができます。
from blog.models import RedArticle RedArticle.objects.create( title='赤い記事', )
また↓のようにテンプレートファイルで参照可能です。
<h1>{{ article.title }}</h1> <p>作成日: {{ article.created }}</p> <p>更新日: {{ article.modified }}</p>
auto_now_add, auto_nowは使うべきか?
実はこの2つの引数は過去から長年にわたってDjangoコミュニティで議論されてきた引数らしく、ネットにはこれらの引数を使うべきではないという意見もあります。
つまり、廃止されるかもしれないので他の方法を使え、ということです。
私は気にせず使っちゃっているんですが、気になるかたは後述の「save()
を改造して更新する」を参照してください。
save()を改造して更新する
created
やmodified
に自動で日付を入れたい場合は、↓のようにモデルのsave()
メソッドを改造する方法が考えられます。
from django.db import models from django.utils import timezone class PurpleArticle(models.Model): title = models.CharField(max_length=128, help_text='記事のタイトル') created = models.DateTimeField(help_text='作成日') modified = models.DateTimeField(help_text='更新日') def save(self, *args, **kwargs): if not self.id: self.created = timezone.now() # 新規作成時の時刻を保存 self.modified = timezone.now() # 保存されるたびに更新 return super(PurpleArticle, self).save(*args, **kwargs)
この方法が今のところ特に批判も無いベターな方法のようです。
dateフィルターで日付のフォーマットを指定する
created
やmodified
などのDateTimeFieldのフィールドはテンプレートファイル内で参照できますが、そのまま出力すると日本ではあまりなじみのない表記になってしまいます。
そのためdate
フィルターを使って馴染みのあるフォーマットに修正する必要が出てきます。
date
フィルターは↓のように使います。
<h1>{{ article.title }}</h1> <p>dateフィルターを使うと↓のように表示できる。</p> <p>作成日: {{ article.created | date:'Y/m/d H:i' }}</p> <p>更新日: {{ article.modified | date:'y/m/d H:i:s' }}</p>
↑のテンプレートファイルを描画すると↓のような表示の画面になります。
おわりに
今回はDjangoのDateTimeFieldを見てみました。
DjangoのDateTimeField関連の処理はいろいろと非推奨な方法なども散見できて、どれを使えばいいのかわからない感じになってます。
この記事が何かの参考になれば幸いです。
(^ _ ^) | 時刻処理を甘く見るプログラマーは |
(・ v ・) | 痛い目を見る |