You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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 makemigrations
  • python 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 14:39:01