如何使用Django和PostgreSQL实现员工自动考勤打卡系统
基于Django+PostgreSQL实现员工考勤打卡功能的操作步骤
1. 数据库模型配置(models.py)
首先定义考勤表结构,添加联合唯一约束避免同一员工当日生成多条重复考勤记录:
from django.db import models from django.contrib.auth.models import User from django.utils import timezone class AttendanceRecord(models.Model): employee = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="关联员工") attendance_date = models.DateField(default=timezone.localdate, verbose_name="考勤日期") attendance_in = models.DateTimeField(null=True, blank=True, verbose_name="上班打卡时间") attendance_out = models.DateTimeField(null=True, blank=True, verbose_name="下班打卡时间") class Meta: # 联合唯一约束:同一员工单日仅能有一条考勤记录 constraints = [ models.UniqueConstraint(fields=['employee', 'attendance_date'], name='unique_employee_daily_record') ] db_table = "attendance_record"
写完后执行两条命令同步表结构到PostgreSQL:
python manage.py makemigrationspython manage.py migrate
2. 业务逻辑编写(views.py)
实现打卡校验逻辑,避免重复打卡、未上班先打下班卡的异常情况:
from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required from django.utils import timezone from django.contrib import messages from .models import AttendanceRecord # 考勤页面加载逻辑 @login_required def attendance_page(request): today = timezone.localdate() # 存在当日记录就返回,不存在就自动创建 record, created = AttendanceRecord.objects.get_or_create( employee=request.user, attendance_date=today ) return render(request, "attendance.html", {"today_record": record}) # 上班打卡逻辑 @login_required def clock_in(request): if request.method == "POST": today = timezone.localdate() record = AttendanceRecord.objects.get(employee=request.user, attendance_date=today) if record.attendance_in: messages.error(request, "今日已完成上班打卡,无需重复操作") return redirect("attendance_page") record.attendance_in = timezone.localtime() record.save() messages.success(request, "上班打卡成功") return redirect("attendance_page") # 下班打卡逻辑 @login_required def clock_out(request): if request.method == "POST": today = timezone.localdate() record = AttendanceRecord.objects.get(employee=request.user, attendance_date=today) if not record.attendance_in: messages.error(request, "今日未打卡上班,无法提交下班打卡") return redirect("attendance_page") if record.attendance_out: messages.error(request, "今日已完成下班打卡,无需重复操作") return redirect("attendance_page") record.attendance_out = timezone.localtime() record.save() messages.success(request, "下班打卡成功") return redirect("attendance_page")
3. 路由配置(urls.py)
绑定页面和打卡接口的访问路径:
from django.urls import path from . import views urlpatterns = [ path("attendance/", views.attendance_page, name="attendance_page"), path("clock-in/", views.clock_in, name="clock_in"), path("clock-out/", views.clock_out, name="clock_out"), ]
4. 前端打卡页面(templates/attendance.html)
实现两个打卡按钮,根据当日打卡状态自动禁用已完成的操作按钮:
<!DOCTYPE html> <html> <head> <title>员工考勤系统</title> </head> <body> <h2>您好,{{ request.user.username }}</h2> <!-- 操作提示展示 --> {% if messages %} {% for msg in messages %} <p>{{ msg }}</p> {% endfor %} {% endif %} <div style="margin-top: 40px;"> <form method="post" action="{% url 'clock_in' %}" style="margin-right: 30px;display: inline-block;"> {% csrf_token %} <button type="submit" {% if today_record.attendance_in %}disabled{% endif %}>上班打卡</button> {% if today_record.attendance_in %} <span>已打卡:{{ today_record.attendance_in|date:"Y-m-d H:i:s" }}</span> {% endif %} </form> <form method="post" action="{% url 'clock_out' %}" style="display: inline-block;"> {% csrf_token %} <button type="submit" {% if today_record.attendance_out or not today_record.attendance_in %}disabled{% endif %}>下班打卡</button> {% if today_record.attendance_out %} <span>已打卡:{{ today_record.attendance_out|date:"Y-m-d H:i:s" }}</span> {% endif %} </form> </div> </body> </html>
异常排查注意事项
- 确保settings.py中PostgreSQL配置正确,库名、用户名、密码、端口信息和实际数据库一致
- 时区配置要正确,在settings.py中设置
TIME_ZONE = "Asia/Shanghai"、USE_TZ = True,避免打卡时间时区错误 - 若出现重复创建当日记录的问题,检查模型中的联合唯一约束是否正常生效
内容的提问来源于stack exchange,提问作者haris salamat
相关产品推荐
相关产品推荐

