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

如何用django-tables2实现基于单模型的二维出勤表格?

嘿,我懂你想要实现的这种学生出勤透视表需求——把每条分散的出勤记录转换成行是学生、列是日期的二维表格对吧?我之前做项目时也遇到过一模一样的问题,咱们一步步来搞定它!

实现学生×日期的出勤透视表方案

首先要明确:你当前的表格是把单条出勤记录作为一行,而目标是把日期转成动态列、学生作为固定行,所以核心是先对数据做「透视转换」,再用django-tables2渲染动态列。

1. 先在视图里整理透视数据

先获取需要展示的日期范围和所有学生,再为每个学生匹配对应日期的出勤状态,把数据转换成表格需要的结构:

from django.utils import timezone
from .models import DailyAttendanceStudent
from perfiles.models import Student
from datetime import timedelta

def attendance_table_view(request):
    # 示例:获取最近7天的日期(可根据需求调整范围)
    end_date = timezone.localdate()
    start_date = end_date - timedelta(days=6)
    date_range = [start_date + timedelta(days=i) for i in range((end_date - start_date).days + 1)]
    
    # 获取所有需要展示的学生
    students = Student.objects.all()
    
    # 批量查询所有出勤记录,用字典映射优化性能(避免循环查库)
    attendance_records = DailyAttendanceStudent.objects.filter(date__range=[start_date, end_date])
    attendance_map = {(a.student_id, a.date): a.get_status_display() for a in attendance_records}
    
    # 构建透视表数据:每个学生对应一条包含姓名+各日期状态的记录
    pivot_data = []
    for student in students:
        student_row = {
            'first_name': student.first_name,
            'last_name': student.last_name,
        }
        # 为每个日期填充出勤状态
        for date in date_range:
            student_row[str(date)] = attendance_map.get((student.id, date), '')
        pivot_data.append(student_row)
    
    return render(request, 'attendance_table.html', {'pivot_data': pivot_data, 'date_range': date_range})

2. 动态生成表格类

因为日期列是动态变化的,不能硬编码在表格类里,所以要在视图里动态创建表格结构:

import django_tables2 as tables
from django.utils.safestring import mark_safe

def attendance_table_view(request):
    # 上面的数据整理代码...
    
    # 定义表格基础列(学生姓名)
    class DynamicAttendanceTable(tables.Table):
        first_name = tables.Column(verbose_name='Nombres')
        last_name = tables.Column(verbose_name='Apellidos')
    
    # 自定义状态渲染函数(可选,给不同状态加样式)
    def render_attendance_status(value):
        if value == 'Presente':
            return mark_safe('<span class="text-success fw-bold">Presente</span>')
        elif value == 'Ausente':
            return mark_safe('<span class="text-danger fw-bold">Ausente</span>')
        return '-'
    
    # 为每个日期添加动态列
    for date in date_range:
        date_str = str(date)
        # 添加日期列,设置显示格式和渲染逻辑
        DynamicAttendanceTable.base_columns[date_str] = tables.Column(
            verbose_name=date.strftime('%d/%m/%Y'),
            render=render_attendance_status
        )
    
    # 初始化表格
    table = DynamicAttendanceTable(pivot_data)
    
    return render(request, 'attendance_table.html', {'table': table})

3. 模板里渲染表格

在attendance_table.html模板中,用django-tables2的标签直接渲染:

{% load django_tables2 %}
<div class="container mt-4">
    {% render_table table %}
</div>

额外优化提示

  • 如果数据量很大,建议给DailyAttendanceStudent模型的student和date字段加联合索引,提升查询速度:
    class DailyAttendanceStudent(models.Model):
        # 原有字段...
        class Meta:
            indexes = [
                models.Index(fields=['student', 'date']),
            ]
    
  • 可以根据需求调整日期范围的筛选逻辑,比如从请求参数里接收开始/结束日期,或者按学期筛选。

这样就能实现你想要的「行是学生、列是日期、单元格是出勤状态」的表格效果啦!

内容的提问来源于stack exchange,提问作者Marcelo Meza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:37:03