Compare commits
No commits in common. 'main' and 'master' have entirely different histories.
@ -0,0 +1,3 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.11" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.12 (PythonProject)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11" project-jdk-type="Python SDK" />
|
||||
</project>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/PythonProject.iml" filepath="$PROJECT_DIR$/.idea/PythonProject.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,173 @@
|
||||
from datetime import date
|
||||
from typing import List, Optional, Dict
|
||||
from copy import deepcopy
|
||||
from model.student import Student
|
||||
from DAL.clear_all_student import IStudentDAL
|
||||
|
||||
|
||||
|
||||
class StudentBLL:
|
||||
def __init__(self, dal: IStudentDAL):
|
||||
self.dal = dal
|
||||
|
||||
def add_student(self, student: Student) -> bool:
|
||||
"""添加学生信息,进行完整校验和唯一性检查"""
|
||||
# 1. 数据校验
|
||||
if not student.is_valid:
|
||||
raise ValueError(f"学生数据校验不通过。错误信息: {student.get_errors()}")
|
||||
|
||||
# 2. 唯一性检查
|
||||
if self.dal.check_student_exists_by_id_card(student.id_card):
|
||||
raise ValueError(f"身份证号 {student.id_card} 已存在")
|
||||
if self.dal.check_student_exists_by_stu_id(student.stu_id):
|
||||
raise ValueError(f"学号 {student.stu_id} 已存在")
|
||||
|
||||
# 3. 业务规则检查
|
||||
today = date.today()
|
||||
if student.birth_date and student.birth_date > today:
|
||||
raise ValueError("出生日期不能晚于当前日期")
|
||||
if student.enrollment_date and student.enrollment_date > today:
|
||||
raise ValueError("入学日期不能晚于当前日期")
|
||||
if student.height and (student.height <= 0 or student.height > 250):
|
||||
raise ValueError("身高必须在0-250厘米之间")
|
||||
if student.weight and (student.weight <= 0 or student.weight > 300):
|
||||
raise ValueError("体重必须在0-300公斤之间")
|
||||
|
||||
# 4. 添加学生
|
||||
return self.dal.add_student(student)
|
||||
|
||||
def delete_student_by_id_card(self, id_card: str) -> bool:
|
||||
"""根据身份证号删除学生信息"""
|
||||
if not self.dal.check_student_exists_by_id_card(id_card):
|
||||
raise ValueError(f"身份证号 {id_card} 不存在")
|
||||
return self.dal.delete_student_by_id_card(id_card)
|
||||
|
||||
def delete_student_by_stu_id(self, stu_id: str) -> bool:
|
||||
"""根据学号删除学生信息"""
|
||||
if not self.dal.check_student_exists_by_stu_id(stu_id):
|
||||
raise ValueError(f"学号 {stu_id} 不存在")
|
||||
return self.dal.delete_student_by_stu_id(stu_id)
|
||||
|
||||
def update_student(self, id_card: str, student: Student) -> bool:
|
||||
"""完整更新学生信息"""
|
||||
# 1. 存在性检查
|
||||
if not self.dal.check_student_exists_by_id_card(id_card):
|
||||
raise ValueError(f"身份证号 {id_card} 不存在")
|
||||
|
||||
# 2. 数据校验
|
||||
if not student.is_valid:
|
||||
raise ValueError(f"学生数据校验不通过。错误信息: {student.get_errors()}")
|
||||
|
||||
# 3. 业务规则检查
|
||||
today = date.today()
|
||||
if student.birth_date and student.birth_date > today:
|
||||
raise ValueError("出生日期不能晚于当前日期")
|
||||
if student.enrollment_date and student.enrollment_date > today:
|
||||
raise ValueError("入学日期不能晚于当前日期")
|
||||
if student.height and (student.height <= 0 or student.height > 250):
|
||||
raise ValueError("身高必须在0-250厘米之间")
|
||||
if student.weight and (student.weight <= 0 or student.weight > 300):
|
||||
raise ValueError("体重必须在0-300公斤之间")
|
||||
|
||||
# 4. 执行更新
|
||||
return self.dal.update_student(id_card, student)
|
||||
|
||||
def update_student_partial(self, id_card: str, **kwargs) -> bool:
|
||||
"""部分更新学生信息"""
|
||||
# 1. 存在性检查
|
||||
student = self.dal.find_student_by_id_card(id_card)
|
||||
if not student:
|
||||
raise ValueError(f"身份证号 {id_card} 不存在")
|
||||
|
||||
# 2. 保护关键字段 - 身份证号不可更改
|
||||
if 'id_card' in kwargs:
|
||||
raise ValueError("身份证号不可更改")
|
||||
|
||||
# 3. 创建更新后的学生对象
|
||||
updated_student = deepcopy(student)
|
||||
for key, value in kwargs.items():
|
||||
if hasattr(updated_student, key):
|
||||
setattr(updated_student, key, value)
|
||||
|
||||
# 4. 数据校验
|
||||
if not updated_student.is_valid:
|
||||
raise ValueError(f"学生数据校验不通过。错误信息: {updated_student.get_errors()}")
|
||||
|
||||
# 5. 业务规则检查
|
||||
today = date.today()
|
||||
if updated_student.birth_date and updated_student.birth_date > today:
|
||||
raise ValueError("出生日期不能晚于当前日期")
|
||||
if updated_student.enrollment_date and updated_student.enrollment_date > today:
|
||||
raise ValueError("入学日期不能晚于当前日期")
|
||||
if updated_student.height and (updated_student.height <= 0 or updated_student.height > 250):
|
||||
raise ValueError("身高必须在0-250厘米之间")
|
||||
if updated_student.weight and (updated_student.weight <= 0 or updated_student.weight > 300):
|
||||
raise ValueError("体重必须在0-300公斤之间")
|
||||
|
||||
# 6. 学号唯一性检查(如果学号有变化)
|
||||
if 'stu_id' in kwargs and kwargs['stu_id'] != student.stu_id:
|
||||
if self.dal.check_student_exists_by_stu_id(kwargs['stu_id']):
|
||||
raise ValueError(f"学号 {kwargs['stu_id']} 已存在")
|
||||
|
||||
# 7. 执行更新
|
||||
return self.dal.update_student(id_card, updated_student)
|
||||
|
||||
def get_student_by_id_card(self, id_card: str) -> Optional[Student]:
|
||||
"""根据身份证号查询学生信息"""
|
||||
return self.dal.find_student_by_id_card(id_card)
|
||||
|
||||
def get_student_by_stu_id(self, stu_id: str) -> Optional[Student]:
|
||||
"""根据学号查询学生信息"""
|
||||
return self.dal.find_student_by_stu_id(stu_id)
|
||||
|
||||
def get_students_by_name(self, name: str) -> List[Student]:
|
||||
"""根据姓名查询学生信息(模糊匹配)"""
|
||||
return self.dal.find_students_by_name(name)
|
||||
|
||||
def get_students_by_class_name(self, class_name: str) -> List[Student]:
|
||||
"""根据班级名称查询学生信息(模糊匹配)"""
|
||||
return self.dal.find_students_by_class_name(class_name)
|
||||
|
||||
def get_students_by_major(self, major: str) -> List[Student]:
|
||||
"""根据专业查询学生信息(模糊匹配)"""
|
||||
return self.dal.find_students_by_major(major)
|
||||
|
||||
def get_all_students(self) -> List[Student]:
|
||||
"""获取所有学生信息"""
|
||||
return self.dal.get_all_students()
|
||||
|
||||
def get_student_count(self) -> int:
|
||||
"""获取学生总数"""
|
||||
return self.dal.get_student_count()
|
||||
|
||||
def get_students_by_height_range(self, min_height: int, max_height: int) -> List[Student]:
|
||||
"""按身高范围查询学生"""
|
||||
return self.dal.get_students_by_height_range(min_height, max_height)
|
||||
|
||||
def get_students_by_enrollment_year(self, year: int) -> List[Student]:
|
||||
"""按入学年份查询学生"""
|
||||
return self.dal.get_students_by_enrollment_year(year)
|
||||
|
||||
def get_students_by_age_range(self, min_age: int, max_age: int) -> List[Student]:
|
||||
"""按年龄范围查询学生"""
|
||||
return self.dal.get_students_by_age_range(min_age, max_age)
|
||||
|
||||
def get_students_by_major_group(self) -> Dict[str, List[Student]]:
|
||||
"""按专业分组学生"""
|
||||
return self.dal.get_students_by_major_group()
|
||||
|
||||
def get_average_height(self) -> float:
|
||||
"""计算平均身高"""
|
||||
return self.dal.get_average_height()
|
||||
|
||||
def get_average_weight(self) -> float:
|
||||
"""计算平均体重"""
|
||||
return self.dal.get_average_weight()
|
||||
|
||||
def get_gender_ratio(self) -> Dict[Optional[bool], float]:
|
||||
"""计算性别比例"""
|
||||
return self.dal.get_gender_ratio()
|
||||
|
||||
def clear_all_students(self) -> None:
|
||||
"""清空所有学生信息"""
|
||||
self.dal.clear_all_students()
|
@ -0,0 +1,476 @@
|
||||
import os
|
||||
import json
|
||||
import csv
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import date
|
||||
from typing import List, Optional, Dict
|
||||
from model.student import Student
|
||||
|
||||
class IStudentDAL(ABC):
|
||||
"""学生信息数据访问层接口"""
|
||||
|
||||
@abstractmethod
|
||||
def add_student(self, student: Student) -> bool:
|
||||
"""添加学生"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_student_by_id_card(self, id_card: str) -> bool:
|
||||
"""根据身份证号删除学生"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete_student_by_stu_id(self, stu_id: str) -> bool:
|
||||
"""根据学号删除学生"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update_student(self, id_card: str, updated_student: Student) -> bool:
|
||||
"""更新学生信息"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def find_student_by_id_card(self, id_card: str) -> Optional[Student]:
|
||||
"""根据身份证号查找学生"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def find_student_by_stu_id(self, stu_id: str) -> Optional[Student]:
|
||||
"""根据学号查找学生"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def find_students_by_name(self, name: str) -> List[Student]:
|
||||
"""根据姓名查找学生(模糊匹配)"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def find_students_by_class_name(self, class_name: str) -> List[Student]:
|
||||
"""根据班级名称查找学生(模糊匹配)"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def find_students_by_major(self, major: str) -> List[Student]:
|
||||
"""根据专业查找学生(模糊匹配)"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_all_students(self) -> List[Student]:
|
||||
"""获取所有学生信息"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_student_count(self) -> int:
|
||||
"""获取学生总数"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_students_by_height_range(self, min_height: int, max_height: int) -> List[Student]:
|
||||
"""按身高范围查找学生"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_students_by_enrollment_year(self, year: int) -> List[Student]:
|
||||
"""按入学年份查找学生"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_students_by_age_range(self, min_age: int, max_age: int) -> List[Student]:
|
||||
"""按年龄范围查找学生"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_students_by_major_group(self) -> Dict[str, List[Student]]:
|
||||
"""按专业分组学生"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_average_height(self) -> float:
|
||||
"""计算平均身高"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_average_weight(self) -> float:
|
||||
"""计算平均体重"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_gender_ratio(self) -> Dict[Optional[bool], float]:
|
||||
"""计算性别比例"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def clear_all_students(self) -> None:
|
||||
"""清空所有学生信息"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def check_student_exists_by_id_card(self, id_card: str) -> bool:
|
||||
"""检查身份证号是否存在"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def check_student_exists_by_stu_id(self, stu_id: str) -> bool:
|
||||
"""检查学号是否存在"""
|
||||
pass
|
||||
|
||||
|
||||
class JsonStudentDAL(IStudentDAL):
|
||||
"""JSON文件存储实现"""
|
||||
|
||||
def __init__(self, file_path: str):
|
||||
self.file_path = file_path
|
||||
self.__ensure_file_exists()
|
||||
|
||||
def __ensure_file_exists(self):
|
||||
"""确保JSON文件存在"""
|
||||
if not os.path.exists(self.file_path):
|
||||
with open(self.file_path, 'w', encoding='utf-8') as file:
|
||||
# noinspection PyTypeChecker
|
||||
json.dump([], file)
|
||||
|
||||
def __load_students(self) -> List[Student]:
|
||||
"""从JSON文件加载学生列表"""
|
||||
try:
|
||||
with open(self.file_path, 'r', encoding='utf-8') as file:
|
||||
student_dicts = json.load(file)
|
||||
return [Student.from_dict(sd) for sd in student_dicts]
|
||||
except json.JSONDecodeError:
|
||||
return []
|
||||
|
||||
def __save_students(self, students: List[Student]) -> None:
|
||||
"""将学生列表保存到JSON文件"""
|
||||
student_dicts = [s.to_dict() for s in students]
|
||||
with open(self.file_path, 'w', encoding='utf-8') as file:
|
||||
json.dump(student_dicts, file, ensure_ascii=False, indent=4)
|
||||
|
||||
# 实现接口方法
|
||||
def add_student(self, student: Student) -> bool:
|
||||
students = self.__load_students()
|
||||
if any(s.id_card == student.id_card for s in students):
|
||||
return False
|
||||
if any(s.stu_id == student.stu_id for s in students):
|
||||
return False
|
||||
students.append(student)
|
||||
self.__save_students(students)
|
||||
return True
|
||||
|
||||
def delete_student_by_id_card(self, id_card: str) -> bool:
|
||||
students = self.__load_students()
|
||||
original_count = len(students)
|
||||
students = [s for s in students if s.id_card != id_card]
|
||||
if len(students) < original_count:
|
||||
self.__save_students(students)
|
||||
return True
|
||||
return False
|
||||
|
||||
def delete_student_by_stu_id(self, stu_id: str) -> bool:
|
||||
students = self.__load_students()
|
||||
original_count = len(students)
|
||||
students = [s for s in students if s.stu_id != stu_id]
|
||||
if len(students) < original_count:
|
||||
self.__save_students(students)
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_student(self, id_card: str, updated_student: Student) -> bool:
|
||||
students = self.__load_students()
|
||||
for i, s in enumerate(students):
|
||||
if s.id_card == id_card:
|
||||
students[i] = updated_student
|
||||
self.__save_students(students)
|
||||
return True
|
||||
return False
|
||||
|
||||
def find_student_by_id_card(self, id_card: str) -> Optional[Student]:
|
||||
students = self.__load_students()
|
||||
for s in students:
|
||||
if s.id_card == id_card:
|
||||
return s
|
||||
return None
|
||||
|
||||
def find_student_by_stu_id(self, stu_id: str) -> Optional[Student]:
|
||||
students = self.__load_students()
|
||||
for s in students:
|
||||
if s.stu_id == stu_id:
|
||||
return s
|
||||
return None
|
||||
|
||||
def find_students_by_name(self, name: str) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
return [s for s in students if name.lower() in s.name.lower()]
|
||||
|
||||
def find_students_by_class_name(self, class_name: str) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
return [s for s in students if s.class_name and class_name.lower() in s.class_name.lower()]
|
||||
|
||||
def find_students_by_major(self, major: str) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
return [s for s in students if s.major and major.lower() in s.major.lower()]
|
||||
|
||||
def get_all_students(self) -> List[Student]:
|
||||
return self.__load_students()
|
||||
|
||||
def get_student_count(self) -> int:
|
||||
return len(self.__load_students())
|
||||
|
||||
def get_students_by_height_range(self, min_height: int, max_height: int) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
return [s for s in students if s.height and min_height <= s.height <= max_height]
|
||||
|
||||
def get_students_by_enrollment_year(self, year: int) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
return [s for s in students if s.enrollment_date and s.enrollment_date.year == year]
|
||||
|
||||
def get_students_by_age_range(self, min_age: int, max_age: int) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
today = date.today()
|
||||
result = []
|
||||
for s in students:
|
||||
if s.birth_date:
|
||||
age = today.year - s.birth_date.year
|
||||
if (today.month, today.day) < (s.birth_date.month, s.birth_date.day):
|
||||
age -= 1
|
||||
if min_age <= age <= max_age:
|
||||
result.append(s)
|
||||
return result
|
||||
|
||||
def get_students_by_major_group(self) -> Dict[str, List[Student]]:
|
||||
students = self.__load_students()
|
||||
groups = {}
|
||||
for s in students:
|
||||
if s.major:
|
||||
if s.major not in groups:
|
||||
groups[s.major] = []
|
||||
groups[s.major].append(s)
|
||||
return groups
|
||||
|
||||
def get_average_height(self) -> float:
|
||||
students = self.__load_students()
|
||||
heights = [s.height for s in students if s.height is not None]
|
||||
if not heights:
|
||||
return 0.0
|
||||
return sum(heights) / len(heights)
|
||||
|
||||
def get_average_weight(self) -> float:
|
||||
students = self.__load_students()
|
||||
weights = [s.weight for s in students if s.weight is not None]
|
||||
if not weights:
|
||||
return 0.0
|
||||
return sum(weights) / len(weights)
|
||||
|
||||
def get_gender_ratio(self) -> Dict[Optional[bool], float]:
|
||||
students = self.__load_students()
|
||||
genders = [s.gender for s in students if s.gender is not None]
|
||||
total = len(genders)
|
||||
if total == 0:
|
||||
return {True: 0.0, False: 0.0}
|
||||
|
||||
male_count = sum(1 for g in genders if g)
|
||||
female_count = total - male_count
|
||||
return {
|
||||
True: male_count / total * 100,
|
||||
False: female_count / total * 100
|
||||
}
|
||||
|
||||
def clear_all_students(self) -> None:
|
||||
self.__save_students([])
|
||||
|
||||
def check_student_exists_by_id_card(self, id_card: str) -> bool:
|
||||
return self.find_student_by_id_card(id_card) is not None
|
||||
|
||||
def check_student_exists_by_stu_id(self, stu_id: str) -> bool:
|
||||
return self.find_student_by_stu_id(stu_id) is not None
|
||||
|
||||
|
||||
class CsvStudentDAL(IStudentDAL):
|
||||
"""CSV文件存储实现"""
|
||||
|
||||
def __init__(self, file_path: str):
|
||||
self.file_path = file_path
|
||||
self.__ensure_file_exists()
|
||||
|
||||
def __ensure_file_exists(self):
|
||||
"""确保CSV文件存在"""
|
||||
if not os.path.exists(self.file_path):
|
||||
with open(self.file_path, 'w', encoding='utf-8', newline='') as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow([
|
||||
'name', 'id_card', 'stu_id', 'gender', 'height', 'weight',
|
||||
'enrollment_date', 'class_name', 'major', 'email', 'phone'
|
||||
])
|
||||
|
||||
def __load_students(self) -> List[Student]:
|
||||
"""从CSV文件加载学生列表"""
|
||||
students = []
|
||||
try:
|
||||
with open(self.file_path, 'r', encoding='utf-8', newline='') as file:
|
||||
reader = csv.DictReader(file)
|
||||
for row in reader:
|
||||
# 转换数据类型
|
||||
if row['gender']:
|
||||
row['gender'] = True if row['gender'] == 'True' else False
|
||||
|
||||
if row['height']:
|
||||
row['height'] = int(row['height'])
|
||||
|
||||
if row['weight']:
|
||||
row['weight'] = float(row['weight'])
|
||||
|
||||
if row['enrollment_date']:
|
||||
row['enrollment_date'] = date.fromisoformat(row['enrollment_date'])
|
||||
|
||||
students.append(Student.from_dict(row))
|
||||
except (FileNotFoundError, csv.Error, ValueError):
|
||||
pass
|
||||
return students
|
||||
|
||||
def __save_students(self, students: List[Student]) -> None:
|
||||
"""将学生列表保存到CSV文件"""
|
||||
with open(self.file_path, 'w', encoding='utf-8', newline='') as file:
|
||||
fieldnames = [
|
||||
'name', 'id_card', 'stu_id', 'gender', 'height', 'weight',
|
||||
'enrollment_date', 'class_name', 'major', 'email', 'phone'
|
||||
]
|
||||
writer = csv.DictWriter(file, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
for student in students:
|
||||
writer.writerow(student.to_dict())
|
||||
|
||||
# 实现接口方法
|
||||
def add_student(self, student: Student) -> bool:
|
||||
students = self.__load_students()
|
||||
if any(s.id_card == student.id_card for s in students):
|
||||
return False
|
||||
if any(s.stu_id == student.stu_id for s in students):
|
||||
return False
|
||||
students.append(student)
|
||||
self.__save_students(students)
|
||||
return True
|
||||
|
||||
def delete_student_by_id_card(self, id_card: str) -> bool:
|
||||
students = self.__load_students()
|
||||
original_count = len(students)
|
||||
students = [s for s in students if s.id_card != id_card]
|
||||
if len(students) < original_count:
|
||||
self.__save_students(students)
|
||||
return True
|
||||
return False
|
||||
|
||||
def delete_student_by_stu_id(self, stu_id: str) -> bool:
|
||||
students = self.__load_students()
|
||||
original_count = len(students)
|
||||
students = [s for s in students if s.stu_id != stu_id]
|
||||
if len(students) < original_count:
|
||||
self.__save_students(students)
|
||||
return True
|
||||
return False
|
||||
|
||||
def update_student(self, id_card: str, updated_student: Student) -> bool:
|
||||
students = self.__load_students()
|
||||
for i, s in enumerate(students):
|
||||
if s.id_card == id_card:
|
||||
students[i] = updated_student
|
||||
self.__save_students(students)
|
||||
return True
|
||||
return False
|
||||
|
||||
def find_student_by_id_card(self, id_card: str) -> Optional[Student]:
|
||||
students = self.__load_students()
|
||||
for s in students:
|
||||
if s.id_card == id_card:
|
||||
return s
|
||||
return None
|
||||
|
||||
def find_student_by_stu_id(self, stu_id: str) -> Optional[Student]:
|
||||
students = self.__load_students()
|
||||
for s in students:
|
||||
if s.stu_id == stu_id:
|
||||
return s
|
||||
return None
|
||||
|
||||
def find_students_by_name(self, name: str) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
return [s for s in students if name.lower() in s.name.lower()]
|
||||
|
||||
def find_students_by_class_name(self, class_name: str) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
return [s for s in students if s.class_name and class_name.lower() in s.class_name.lower()]
|
||||
|
||||
def find_students_by_major(self, major: str) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
return [s for s in students if s.major and major.lower() in s.major.lower()]
|
||||
|
||||
def get_all_students(self) -> List[Student]:
|
||||
return self.__load_students()
|
||||
|
||||
def get_student_count(self) -> int:
|
||||
return len(self.__load_students())
|
||||
|
||||
def get_students_by_height_range(self, min_height: int, max_height: int) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
return [s for s in students if s.height and min_height <= s.height <= max_height]
|
||||
|
||||
def get_students_by_enrollment_year(self, year: int) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
return [s for s in students if s.enrollment_date and s.enrollment_date.year == year]
|
||||
|
||||
def get_students_by_age_range(self, min_age: int, max_age: int) -> List[Student]:
|
||||
students = self.__load_students()
|
||||
today = date.today()
|
||||
result = []
|
||||
for s in students:
|
||||
if s.birth_date:
|
||||
age = today.year - s.birth_date.year
|
||||
if (today.month, today.day) < (s.birth_date.month, s.birth_date.day):
|
||||
age -= 1
|
||||
if min_age <= age <= max_age:
|
||||
result.append(s)
|
||||
return result
|
||||
|
||||
def get_students_by_major_group(self) -> Dict[str, List[Student]]:
|
||||
students = self.__load_students()
|
||||
groups = {}
|
||||
for s in students:
|
||||
if s.major:
|
||||
if s.major not in groups:
|
||||
groups[s.major] = []
|
||||
groups[s.major].append(s)
|
||||
return groups
|
||||
|
||||
def get_average_height(self) -> float:
|
||||
students = self.__load_students()
|
||||
heights = [s.height for s in students if s.height is not None]
|
||||
if not heights:
|
||||
return 0.0
|
||||
return sum(heights) / len(heights)
|
||||
|
||||
def get_average_weight(self) -> float:
|
||||
students = self.__load_students()
|
||||
weights = [s.weight for s in students if s.weight is not None]
|
||||
if not weights:
|
||||
return 0.0
|
||||
return sum(weights) / len(weights)
|
||||
|
||||
def get_gender_ratio(self) -> Dict[Optional[bool], float]:
|
||||
students = self.__load_students()
|
||||
genders = [s.gender for s in students if s.gender is not None]
|
||||
total = len(genders)
|
||||
if total == 0:
|
||||
return {True: 0.0, False: 0.0}
|
||||
|
||||
male_count = sum(1 for g in genders if g)
|
||||
female_count = total - male_count
|
||||
return {
|
||||
True: male_count / total * 100,
|
||||
False: female_count / total * 100
|
||||
}
|
||||
|
||||
def clear_all_students(self) -> None:
|
||||
self.__save_students([])
|
||||
|
||||
def check_student_exists_by_id_card(self, id_card: str) -> bool:
|
||||
return self.find_student_by_id_card(id_card) is not None
|
||||
|
||||
def check_student_exists_by_stu_id(self, stu_id: str) -> bool:
|
||||
return self.find_student_by_stu_id(stu_id) is not None
|
@ -0,0 +1,15 @@
|
||||
import os, sys
|
||||
from ui.add_student import StudentTUI
|
||||
|
||||
|
||||
cur_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
project_dir = os.path.dirname(cur_dir)
|
||||
|
||||
sys.path.append(project_dir)
|
||||
|
||||
def main():
|
||||
file_path ='./data/students.json'
|
||||
ui = StudentTUI(file_path)
|
||||
ui.run()
|
||||
if __name__=='__main__':
|
||||
main()
|
|
@ -0,0 +1 @@
|
||||
[]
|
Loading…
Reference in new issue