You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wlhdl/DAL/clear_all_student.py

477 lines
16 KiB

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