\ お問い合わせはこちら! /

【Django】最新の年齢を取得し続ける2つの方法

  • ユーザーの年齢は常に最新の値が欲しい!

このような方に向けて書きました。

本記事では最新の年齢を取得し続けるための方法を解説します。

年齢をデータベースで年齢を管理したい場合にはageフィールドを用意することを考えてしまいがちですが、これでは時間と共に自動的に更新されません。(登録時の年齢しか登録されない)

年齢情報が欲しいケースは「現段階の年齢」が欲しい場合がほとんどなので、今回の動的に実装する方法は便利です。

最新の年齢を取得し続ける2つの方法

実装の方針は次の2パターンです。

  • 年齢をプロパティとして設定
  • 定期的にageフィールドを更新

基本的には❶の方法が推奨ですが、❷の方法も併せて解説します。

年齢をプロパティとして設定

ageフィールドは定義せずに、プロパティとして年齢を計算する方法です。

from django.utils import timezone

class Child(models.Model):
    # 生年月日
    birthdate = models.DateField(
        verbose_name="生年月日",
        blank=True,
        null=True,
    )

    @property
    def age(self):
        # 今日の日付を取得
        today = timezone.now().date()
        # 年齢を計算
        age = today.year - self.birthdate.year
        # 誕生日が来ていない場合は1引く
        if (today.month, today.day) < (self.birthdate.month, self.birthdate.day):
            age -= 1
        return age

フィールドとしては不変の誕生日を持たせておいて、都度年齢を計算します。

メリットは以下の通り。

  • データベースの更新が不要
  • アクセスのたびに正確な年齢が計算できる
  • 年齢と誕生日の情報が分離できる

ここではプロパティとして定義したので、以下のようにして呼び出せるようになります。

# 例: Childインスタンスのageプロパティにアクセス
child = Child.objects.get(id=1)
# メソッド呼び出しではなく、属性としてアクセス
print(child.age)

定期的にageフィールドを更新

データ管理上の理由でageフィールドが欲しい場合もある場合には、定期的にデータベースを更新する方法もあります。

まずはageフィールドを設定。

from django.conf import settings
from django.db import models
from django.core.validators import MinValueValidator


class Child(models.Model):    
    # 年齢
    age = models.PositiveIntegerField(
        blank=True,
        null=True,
        validators=[MinValueValidator(0)],
        help_text="子供の年齢(自動更新されます)",
    )

その上でカスタムコマンドを定義します。

from django.core.management.base import BaseCommand
from django.utils import timezone
from myapp.models import Child

class Command(BaseCommand):
    help = "Update ages for all children"

    def handle(self, *args, **kwargs):
        today = timezone.now().date()
        children = Child.objects.filter(birthdate__isnull=False)
        for child in children:
            age = today.year - child.birthdate.year
            if (today.month, today.day) < (child.birthdate.month, child.birthdate.day):
                age -= 1
            child.age = age
            child.save()
        self.stdout.write(self.style.SUCCESS("Successfully updated ages"))

これを実行する手段としては、大きく次の3つの方法があります。

  • Djangoの管理コマンドを利用
  • Celeryなどのタスクキューを利用
  • データベーストリガーを利用

これらの具体的な方法は、後日記事で方法をご紹介する予定です。

補足:アプリに年齢制限を設ける

たとえば年齢制限をつけたい場合には、ageフィールドを設置する必要があります。

この場合には以下のようなcleanメソッドを追記することがあります。

def clean(self):
    if self.age and self.age < 5:
        raise ValidationError("5歳未満の子供は登録できません。")

まとめ

年齢はプロパティにすることで、常に最新の年齢を取得可能です。

やむなくageフィールドを用意したい場合には、カスタムコマンドを用意して定期実行という流れになります。

カスタムコマンドについては、以下の記事で説明しました。

» 参考:【初心者でも簡単】Djangoカスタムコマンド入門

この記事が気に入ったら
フォローしてね!

シェア・記事の保存はこちら!

この記事を書いた人

karo@プログラマのアバター karo@プログラマ プログラマ

「書くことで人の役にたつ」をモットーに活動中。
本職はプログラマで、Pythonが得意。
基本情報技術者試験合格。

コメント

コメントする

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)