0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Flaskで作る在室表示と集計付きの出席管理システム

Last updated at Posted at 2025-11-03

はじめに

今回は,Flaskによる出席や退室を記録可能な出席管理システムを紹介します.

このシステムは,スマホやPCでWebサイトにアクセスし,出席や退室を記録したりログの蓄積による7日間の出席の集計を確認することができます.

大学の少人数教室や研究室などの十数人単位での授業で出席管理が必要な際に使用可能です.

今回使うFlaskとは,PythonのWebアプリケーションフレームワークであり,小規模向けの簡単なWebアプリケーションを作るのに適しています.

言語・ライブラリ

プログラミング言語はPythonでバージョンは3.12.3
Pythonのライブラリは,datetime,Flask,csv,os,glob
Flaskのバージョンは3.1.2

実装

venvによる仮想環境でPythonのバージョン3.12.3で実装します.

Flaskは以下のように実行し,インストールが確認できれば成功です.
image.png

必要なそれぞれのプログラムは以下の通りです.

Flaskアプリ

Webサイトのバックエンド部分であり,Flaskアプリの作成をしています.

主に,出席や退室のデータを取得し,CSVファイルに名前,状態,時刻を記録し,ログファイルとしてデータの記録を行います.

また,HTMLファイルに取得した出席データや集計データを渡してWebサイトで表示できるように処理を行っています.

app.py

from flask import Flask, render_template, request, redirect
from datetime import datetime, timedelta
import csv, os, glob

app = Flask(__name__)
DATA_DIR = "data"
os.makedirs(DATA_DIR, exist_ok=True)

# --- CSVファイルパス(日付ごと) ---
def get_csv_path():
    today = datetime.now().strftime("%Y%m%d")
    return os.path.join(DATA_DIR, f"attendance_{today}.csv")

# --- CSVへ追記 ---
def write_csv(name, status, time_str):
    path = get_csv_path()
    exists = os.path.exists(path)
    with open(path, "a", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        if not exists:
            writer.writerow(["名前", "状態", "時刻"])
        writer.writerow([name, status, time_str])

# --- 当日分を取得 ---
def read_today():
    path = get_csv_path()
    if not os.path.exists(path):
        return []
    with open(path, encoding="utf-8") as f:
        reader = csv.reader(f)
        next(reader, None)
        return list(reader)

# --- 在室中の人を取得(最後の状態が出席の人) ---
def get_present_people(records):
    latest = {}
    for name, status, time_str in records:
        latest[name] = status
    return [n for n, s in latest.items() if s == "出席"]

@app.route("/")
def index():
    records = read_today()
    present = get_present_people(records)
    return render_template("index.html", records=records, present=present)

@app.route("/submit", methods=["POST"])
def submit():
    name = request.form["name"]
    status = request.form["status"]
    time_str = datetime.now().strftime("%H:%M:%S")

    # 同一人物・同一状態の重複登録を防ぐ
    records = read_today()
    for r in records:
        if r[0] == name and r[1] == status:
            return redirect("/")

    write_csv(name, status, time_str)
    return redirect("/")

# --- 最近7日間の出席集計 ---
@app.route("/summary")
def summary():
    today = datetime.now()
    data = {}
    for i in range(7):
        date = (today - timedelta(days=i)).strftime("%Y%m%d")
        path = os.path.join(DATA_DIR, f"attendance_{date}.csv")
        if os.path.exists(path):
            with open(path, encoding="utf-8") as f:
                reader = csv.reader(f)
                next(reader, None)
                for row in reader:
                    name, status, _ = row
                    if status == "出席":
                        data[name] = data.get(name, 0) + 1
    return render_template("summary.html", data=data)

if __name__ == "__main__":
    app.run(debug=True)

出席・退室登録画面

Webサイトのトップページを表示するためのプログラムです.
出席や退室の登録フォームや記録表示,集計ページへのリンクがあります.

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>出席管理システム</title>
</head>
<body>
  <h1>出席・退席 登録</h1>

  <form action="/submit" method="post">
    <input type="text" name="name" placeholder="名前を入力" required>
    <select name="status">
      <option value="出席">出席</option>
      <option value="退席">退席</option>
    </select>
    <button type="submit">登録</button>
  </form>

  <h2>本日の記録</h2>
  <table border="1">
    <tr><th>名前</th><th>状態</th><th>時刻</th></tr>
    {% for name, status, time in records %}
      <tr><td>{{ name }}</td><td>{{ status }}</td><td>{{ time }}</td></tr>
    {% endfor %}
  </table>

  <h2>現在在室中の人</h2>
  <ul>
    {% for p in present %}
      <li>{{ p }}</li>
    {% endfor %}
  </ul>

  <p><a href="/summary">📅 最近7日間の出席統計を見る</a></p>
</body>
</html>

集計画面

集計ページを表示するためのプログラムです.
過去7日間の集計した出席日数を名前ごとに表示しています.
また,トップページに戻るリンクもあります.

summary.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>出席統計</title>
</head>
<body>
  <h1>最近7日間の出席日数</h1>
  <table border="1">
    <tr><th>名前</th><th>出席日数</th></tr>
    {% for name, count in data.items() %}
      <tr><td>{{ name }}</td><td>{{ count }}</td></tr>
    {% endfor %}
  </table>

  <p><a href="/">← 戻る</a></p>
</body>
</html>

実行環境

今回の実行環境では,Ubuntu22.04を使用し,このシステムをバックグラウンドで常時稼働させるため,サービス化をしています.
サービス化は,Ubuntuでsystemd用のサービスファイルを作成し,設定や反映を行うことで自動起動や常時稼働をするための技術です.
以下のようにサービスファイルを作成し,内容を記述します.

sudo nano /etc/systemd/system/attendance.service
[Unit]
Description=Attendance Flask App
After=network.target

[Service]
User=ユーザー名
Group=ユーザー名
WorkingDirectory=/home/ユーザー名/attendance_system
Environment="PATH=/home/ユーザー名/attendance_system/venv/bin"
ExecStart=/home/ユーザー名/attendance_system/venv/bin/python app.py

Restart=always

[Install]
WantedBy=multi-user.target

反映は以下の順番通りに実行します.

# 新しいサービスを認識させる
sudo systemctl daemon-reload

# サービスを起動
sudo systemctl start attendance

# 自動起動を有効化
sudo systemctl enable attendance

# 動作確認
sudo systemctl status attendance

active(runnning)のようにステータス確認がとれていれば大丈夫です.
image.png

実行手順

ファイルの構成は以下のようになってます.

attendance_system/
├─ app.py
├─ templates/
│   ├─ index.html
│   └─ summary.html
└─ data/
    └─ attendance_YYYYMMDD.csv

まず,app.pyを以下の通りに実行します.

python3 app.py

実行後に http://127.0.0.1:5000 にアクセスしてWebサイトから確認してみてください.

そして,確認後に実際に出席や退室の操作をしてみてください.

ログファイルの確認をする場合は,dataというディレクトリにログが保存されたcsvファイルがあるので確認してみてください.

以下の実行結果のようになったら成功です.

実行結果

Ubuntuコンソール画面

image.png
時刻や "GET HTTP/1.1" 200 - のような表示になっていれば成功です.

Webサイト(トップ画面)

image.png
画像のように本日の記録や現在在室中の人の欄に入力した名前や状態,時刻がそれぞれあれば成功です.

Webサイト(7日間の統計画面)

image.png
名前と日数の欄に入力した数だけカウントされているか確認できれば成功です.
また,トップページに戻れるかも試してみてください.

ログファイル

image.png
名前,状態,時刻がWebサイトと合っているかや入力した名前や時刻が間違っていなければ成功です.

まとめ

今回は,Flaskを使った出席管理システムの紹介を行いました.

このシステムはシンプルで初心者向けなので学習の難易度も高くなく,さまざまな用途に拡張可能です.

出席管理システムのほかにもブログやマイクロサービス構築にも利用できるので,興味があれば挑戦してみるのもいいですね.

参考にしたサイト

https://qiita.com/Bashi50/items/30065e8f54f7e8038323
https://aiacademy.jp/media/?p=57

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?