point_system/point_system/students/models.py
Xiao Furen 750b231a54 feat(students): enhance student management and attendance reporting
Implement several improvements to the student management system, including:
- Add `foreign_alias` and `admission_date` fields to the `Student` model.
- Implement automatic `admission_date` calculation based on `student_id` patterns.
- Enhance attendance reporting with internationalization (i18n) support and improved UI using Bootstrap components.
- Update Excel import logic to support `foreign_alias` and `admission_date` columns.
- Refine weekly schedule synchronization to respect student admission dates.
- Improve the attendance recording interface with better UX and selection controls.
- Update admin interface and templates to display new student attributes.
- Add comprehensive test cases for authentication and protected view access.
2026-08-16 23:03:06 +08:00

91 lines
3.4 KiB
Python

import re
from datetime import date
from django.db import models
DEGREE_CHOICES = [
('學士生', '學士生'),
('碩士生', '碩士生'),
('博士生', '博士生'),
]
CATEGORY_CHOICES = [
('一般生', '一般生'),
('在職生', '在職生'),
('交換中', '交換中'),
]
def calculate_admission_date(student_id):
if not student_id:
return date(date.today().year, 9, 1)
sid = str(student_id).strip()
m_letter = re.match(r'^[A-Za-z]+(\d{2})', sid)
if m_letter:
yy = int(m_letter.group(1))
roc_year = (100 + yy) if yy < 90 else yy
ad_year = roc_year + 1911
return date(ad_year, 9, 1)
m_roc3 = re.match(r'^(\d{3})', sid)
if m_roc3:
roc_year = int(m_roc3.group(1))
ad_year = roc_year + 1911
return date(ad_year, 9, 1)
return date(date.today().year, 9, 1)
class Student(models.Model):
student_id = models.CharField(max_length=10, primary_key=True)
name = models.CharField(max_length=255)
foreign_alias = models.CharField(max_length=255, null=True, blank=True, verbose_name='外文別名')
degree_type = models.CharField(max_length=10, choices=DEGREE_CHOICES, default='碩士生', verbose_name='學位類別')
student_category = models.CharField(max_length=10, choices=CATEGORY_CHOICES, default='一般生', verbose_name='身分類別')
grade = models.IntegerField(null=True, blank=True)
admission_date = models.DateField(null=True, blank=True, verbose_name='入學日期')
hope_admission_scheme = models.BooleanField(default=False, null=True, blank=True)
tuition_waiver = models.BooleanField(default=False, null=True, blank=True)
financial_assistance_disadvantaged_students = models.BooleanField(default=False, null=True, blank=True)
loan = models.IntegerField(null=True, blank=True, default=0)
email = models.EmailField(null=True, blank=True, verbose_name='主要 Email')
email2 = models.EmailField(null=True, blank=True, verbose_name='第二 Email')
is_active = models.BooleanField(default=True)
def save(self, *args, **kwargs):
if not self.admission_date and self.student_id:
self.admission_date = calculate_admission_date(self.student_id)
super().save(*args, **kwargs)
def __str__(self):
return f"{self.name} ({self.degree_type} / {self.student_category})"
class PointRecord(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
datetime = models.DateTimeField(auto_now_add=True) # Combined date and time field
class Meta:
verbose_name = 'point record'
verbose_name_plural = 'point records'
def __str__(self):
return f"{self.datetime} - {self.student}"
class WeeklySchedule(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE, related_name='schedules')
date = models.DateField(verbose_name='週會日期')
year = models.IntegerField(verbose_name='年份')
month = models.IntegerField(verbose_name='月份')
class Meta:
unique_together = ('student', 'date')
verbose_name = '週會排程'
verbose_name_plural = '週會排程'
def save(self, *args, **kwargs):
if self.date:
self.year = self.date.year
self.month = self.date.month
super().save(*args, **kwargs)
def __str__(self):
return f"{self.date} - {self.student.name} ({self.student.student_id})"