naritoブログ

このブログはPython/DjangoとBootstrap4で作成されました
Githubのソースコード

Djangoで、出勤簿

約230日前 2017年12月29日18:31
プログラミング関連
Django Python
今回は、Djangoで出勤簿を作ります。デフォルトで備わっているUserモデルの、ログイン、ログアウトの時間を記録しておけばこれは簡単です。

まず、models.py
from django.conf import settings
from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.db import models
from django.dispatch import receiver
from django.utils import timezone


class AttendanceRecord(models.Model):
    """出勤簿"""

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, verbose_name='ユーザー', on_delete=models.PROTECT)
    login_time = models.DateTimeField('ログイン時刻', blank=True, null=True)
    logout_time = models.DateTimeField('ログアウト時刻', blank=True, null=True)

    def __str__(self):
        login_dt = timezone.localtime(self.login_time)
        return '{0} - {1.year}/{1.month}/{1.day} {1.hour}:{1.minute}:{1.second} - {2}'.format(
            self.user.username, login_dt, self.get_diff_time()
        )

    def get_diff_time(self):
        """ログアウト時間ーログイン時間"""
        if not self.logout_time:
            return 'ログアウトしていません'
        else:
            td = self.logout_time - self.login_time
            return '{0}時間{1}分'.format(
                td.seconds // 3600, (td.seconds // 60) % 60)


@receiver(user_logged_in)
def user_logged_in_callback(sender, request, user, **kwargs):
    """ログインした際に呼ばれる"""
    AttendanceRecord.objects.create(user=user, login_time=timezone.now())


@receiver(user_logged_out)
def user_logged_out_callback(sender, request, user, **kwargs):
    """ログアウトした際に呼ばれる"""
    records = AttendanceRecord.objects.filter(user=user, logout_time__isnull=True)
    if records:
        record = records.latest('pk')
        record.logout_time = timezone.now()
        record.save()




AttendanceRecordが出勤簿となるモデルです。
どのユーザーか、ログイン時間、ログアウト時間の3つのフィールドをもたせます。
__str__では、ユーザー名 - ログイン日付 - 何時間ログインしたか
を表示させます。
例として
narito - 2017/12/29 18:18:46 - ログアウトしていません
のようになります。


基本的に、settings.pyでタイムゾーンを設定していれば、それらは自動的に変換されます。フォームやテンプレートで表示する際には基本的に問題ありません。
が、__str__内で文字列として日付を埋め込むような場合は別です。これは手動で変換する必要があります...
とはいっても、Django側に変換するためのユーティリティ関数があるのでそれが使えます。timezone.localtimeです。
login_dt = timezone.localtime(self.login_time)



get_diff_timeは、何時間ログインしたかを返すメソッドですね。○時間○分 といった形で返すには、このような書き方で充分でしょう。
あくまで日付の差だけわかりゃいいので、こちらはタイムゾーン関連は考慮しなくて良いです。
    def get_diff_time(self):
        """ログアウト時間ーログイン時間"""
        if not self.logout_time:
            return 'ログアウトしていません'
        else:
            td = self.logout_time - self.login_time
            return '{0}時間{1}分'.format(
                td.seconds // 3600, (td.seconds // 60) % 60)



ログインとログアウト時に何らかの処理をするには、以下の2つです。
@receiver(user_logged_in)と、@receiver(user_logged_out)ですね。
@receiver(user_logged_in)
def user_logged_in_callback(sender, request, user, **kwargs):
    """ログインした際に呼ばれる"""
    AttendanceRecord.objects.create(user=user, login_time=timezone.now())


@receiver(user_logged_out)
def user_logged_out_callback(sender, request, user, **kwargs):
    """ログアウトした際に呼ばれる"""
    records = AttendanceRecord.objects.filter(user=user, logout_time__isnull=True)
    if records:
        record = records.latest('pk')
        record.logout_time = timezone.now()
        record.save()




ログアウト時にやることは、ログイン時に作られたAttendanceRecordインスタンスを探すことです。
userが自分で、logout_timeがまだnullのとき...これは、logout_time__isnull=Trueで判別できます。(フィールド名__isnull=True)ですね。
records = AttendanceRecord.objects.filter(user=user, logout_time__isnull=True)



以下のように、良い感じで表示されます。