Djangoで、ログイン・ログアウトの履歴を管理する

Python - Django
2018年11月12日17:02に更新(約1日前)
2018年11月12日16:45に作成(約1日前)

旧ブログ移行記事です。

概要

Djangoにデフォルトで付属したadmin管理サイトやUserモデルは大変便利です。

今回は、このUserモデルのログイン・ログアウトの履歴を管理するアプリケーションを作ります。ちょっとした出勤簿にも使えるかもしれません。

以下のような感じで表示できます。ログイン・ログアウトを管理するモデルを作成します。 /admin管理サイトで履歴を簡単に表示できる

ソースコード

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__では、ユーザー名 - ログイン日付 - 何時間ログインしたかを表示させます。

__str__で日付をタイムゾーン対応

基本的に、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)

ユーザーのログイン・ログアウトイベントをキャッチする

ユーザーのログインとログアウトをキャッチする必要があります。

Djangoにおいては、モデルの保存...saveメソッドの前後で何か処理をしたいならばsignalを使います。

幸いにも、Userモデルのログイン・ログアウトのシグナルは素直に提供されているので、それを使うことができます。@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モデルインスタンスを探すことです。

具体的な条件としては、

  1. ユーザーが自分で
  2. logout_timeがまだnullのとき

です。

これはfilter(user=user, logout_time__isnull=True)で判断することができます。

記事にコメントする