提交项目

z'yzy
员卓豪 1 month ago
commit 1018878da4

3
.idea/.gitignore vendored

@ -0,0 +1,3 @@
# 默认忽略的文件
/shelf/
/workspace.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.11 (PyCharmMiscProject)" />
</component>
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/../PyCharmMiscProject.iml" filepath="$PROJECT_DIR$/../PyCharmMiscProject.iml" />
</modules>
</component>
</project>

@ -0,0 +1,259 @@
import csv
import json
import sqlite3
from abc import ABC, abstractmethod
from datetime import date
from typing import List, Optional, Dict, Any, Union
class Student:
def __init__(self, name: str, id_card: str, stu_id: str, gender: Optional[bool] = None,
height: Optional[int] = None, weight: Optional[float] = None,
enrollment_date: Optional[Union[date, str]] = None,
class_name: Optional[str] = None, major: Optional[str] = None):
self.name = name
self.id_card = id_card
self.stu_id = stu_id
self.gender = gender
self.height = height
self.weight = weight
self.enrollment_date = date.fromisoformat(enrollment_date) if isinstance(enrollment_date,
str) else enrollment_date
self.class_name = class_name
self.major = major
self.age, self.birthday = self._calculate_age_and_birthday()
self._validation_errors = self._validate_all()
def _calculate_age_and_birthday(self) -> tuple[int, date]:
birth_year, birth_month, birth_day = map(int, (self.id_card[6:10], self.id_card[10:12], self.id_card[12:14]))
birthday = date(birth_year, birth_month, birth_day)
today = date.today()
age = today.year - birth_year - ((today.month, today.day) < (birth_month, birth_day))
return age, birthday
def _validate_all(self) -> List[str]:
errors = []
if len(self.id_card) != 18 or not self.id_card[:17].isdigit():
errors.append("身份证号必须为18位数字")
if not self.stu_id:
errors.append("学号不能为空")
if not (2 <= len(self.name) <= 20) or not self.name.isalpha():
errors.append("姓名需为2-20个字母")
if self.enrollment_date and self.enrollment_date < self.birthday:
errors.append("入学日期不能早于出生日期")
if self.height and not 50 <= self.height <= 250:
errors.append("身高需在50-250cm之间")
if self.weight and not 5 <= self.weight <= 300:
errors.append("体重需在5-300kg之间")
return errors
@property
def is_valid(self) -> bool:
return not self._validation_errors
def to_dict(self) -> Dict[str, Any]:
return {
'name': self.name, 'id_card': self.id_card, 'stu_id': self.stu_id,
'gender': self.gender, 'height': self.height, 'weight': self.weight,
'enrollment_date': self.enrollment_date.isoformat() if self.enrollment_date else None,
'class_name': self.class_name, 'major': self.major,
'age': self.age, 'birthday': self.birthday.isoformat()
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'Student':
return cls(**data)
class IStudentDAL(ABC):
@abstractmethod
def get_by_id(self, id_card: str) -> Optional[Student]: ...
@abstractmethod
def get_by_stu_id(self, stu_id: str) -> Optional[Student]: ...
@abstractmethod
def get_all(self) -> List[Student]: ...
@abstractmethod
def add(self, student: Student) -> bool: ...
@abstractmethod
def delete(self, id_card: str = None, stu_id: str = None) -> bool: ...
@abstractmethod
def update(self, student: Student) -> bool: ...
class BaseDAL(IStudentDAL):
def __init__(self, file_path: str):
self.file_path = file_path
self._init_storage()
def _init_storage(self): pass
def get_by_stu_id(self, stu_id: str) -> Optional[Student]:
return next((s for s in self.get_all() if s.stu_id == stu_id), None)
class CSVStudentDAL(BaseDAL):
def _init_storage(self):
with open(self.file_path, 'a') as f: pass # Ensure file exists
def get_all(self) -> List[Student]:
with open(self.file_path, 'r') as f:
return [Student.from_dict(row) for row in csv.DictReader(f)]
def add(self, student: Student) -> bool:
if self.get_by_id(student.id_card) or self.get_by_stu_id(student.stu_id):
return False
with open(self.file_path, 'a', newline='') as f:
writer = csv.DictWriter(f, fieldnames=student.to_dict().keys())
if f.tell() == 0: writer.writeheader()
writer.writerow(student.to_dict())
return True
def delete(self, id_card: str = None, stu_id: str = None) -> bool:
students = [s for s in self.get_all()
if not ((id_card and s.id_card == id_card) or (stu_id and s.stu_id == stu_id))]
with open(self.file_path, 'w', newline='') as f:
if students:
writer = csv.DictWriter(f, fieldnames=students[0].to_dict().keys())
writer.writeheader()
writer.writerows(s.to_dict() for s in students)
return len(students) < len(self.get_all())
class JSONStudentDAL(BaseDAL):
def _init_storage(self):
with open(self.file_path, 'a') as f: pass
def get_all(self) -> List[Student]:
with open(self.file_path, 'r') as f:
return [Student.from_dict(row) for row in json.load(f)]
def add(self, student: Student) -> bool:
data = self.get_all()
if any(s.id_card == student.id_card or s.stu_id == student.stu_id for s in data):
return False
data.append(student)
self._save_all(data)
return True
def _save_all(self, data: List[Student]):
with open(self.file_path, 'w') as f:
json.dump([s.to_dict() for s in data], f, indent=2)
class SQLiteStudentDAL(BaseDAL):
def _init_storage(self):
with sqlite3.connect(self.file_path) as conn:
conn.execute('''
CREATE TABLE IF NOT EXISTS students (
id_card TEXT PRIMARY KEY, stu_id TEXT UNIQUE, name TEXT,
gender BOOLEAN, height INTEGER, weight REAL,
enrollment_date TEXT, class_name TEXT, major TEXT,
age INTEGER, birthday TEXT)''')
def get_all(self) -> List[Student]:
with sqlite3.connect(self.file_path) as conn:
rows = conn.execute("SELECT * FROM students").fetchall()
return [Student.from_dict(dict(zip(('id_card', 'stu_id', 'name', 'gender', 'height',
'weight', 'enrollment_date', 'class_name', 'major',
'age', 'birthday'), row))) for row in rows]
def add(self, student: Student) -> bool:
try:
with sqlite3.connect(self.file_path) as conn:
conn.execute('''
INSERT INTO students VALUES (?,?,?,?,?,?,?,?,?,?,?)''',
(student.id_card, student.stu_id, student.name, student.gender,
student.height, student.weight,
student.enrollment_date.isoformat() if student.enrollment_date else None,
student.class_name, student.major, student.age, student.birthday.isoformat()))
return True
except sqlite3.IntegrityError:
return False
class StudentService:
def __init__(self, dal: IStudentDAL):
self.dal = dal
def add_student(self, student: Student) -> bool:
if not student.is_valid:
raise ValueError(f"Invalid student: {', '.join(student._validation_errors)}")
return self.dal.add(student)
def get_all(self) -> List[Student]:
return self.dal.get_all()
def query(self, **kwargs) -> List[Student]:
return [s for s in self.get_all()
if all(getattr(s, k, None) == v for k, v in kwargs.items() if v)]
def get_stats(self, field: str) -> Dict[str, int]:
return {v: sum(1 for s in self.get_all() if getattr(s, field) == v)
for v in set(getattr(s, field) for s in self.get_all())}
class StudentCLI:
def __init__(self, service: StudentService):
self.service = service
def run(self):
while True:
print("\n1. Add 2. List 3. Query 4. Stats 0. Exit")
choice = input("Choice: ")
if choice == "1":
self._add()
elif choice == "2":
self._list()
elif choice == "3":
self._query()
elif choice == "4":
self._stats()
elif choice == "0":
break
def _add(self):
student = Student(
name=input("Name: "),
id_card=input("ID Card: "),
stu_id=input("Student ID: "),
gender=input("Gender (True/False): ").lower() == 'true',
height=int(input("Height: ")) if input("Height (optional): ") else None,
weight=float(input("Weight: ")) if input("Weight (optional): ") else None
)
try:
if self.service.add_student(student):
print("Added successfully!")
except ValueError as e:
print(f"Error: {e}")
def _list(self):
for student in self.service.get_all():
print(student.to_dict())
def _query(self):
field = input("Field to query (name/class_name/major): ")
value = input(f"{field} value: ")
for student in self.service.query(**{field: value}):
print(student.to_dict())
def _stats(self):
field = input("Field for stats (class_name/major): ")
for k, v in self.service.get_stats(field).items():
print(f"{k}: {v}")
if __name__ == "__main__":
storage = input("Storage (csv/json/sqlite): ").lower()
dal = {
'csv': CSVStudentDAL('students.csv'),
'json': JSONStudentDAL('students.json'),
'sqlite': SQLiteStudentDAL('students.db')
}.get(storage, SQLiteStudentDAL('students.db'))
service = StudentService(dal)
StudentCLI(service).run()

@ -0,0 +1,15 @@
[
{
"name": "\u5458\u5353\u8c6a",
"id_card": "610502200403240018",
"stu_id": "110309230907009",
"gender": false,
"height": 176,
"weight": 62.0,
"enrollment_date": "2023-09-01",
"class_name": "4",
"major": "\u8bf7\u9ad8\u7ea7",
"age": 21,
"birthday": "2004-03-24"
}
]

@ -0,0 +1,836 @@
import csv
import json
import os
import sqlite3
from abc import ABC, abstractmethod
from datetime import date
from typing import List, Optional, Union
# 学生类定义
class Student:
def __init__(self,
name: str,
id_card: str,
stu_id: str,
gender: Optional[bool] = None,
height: Optional[int] = None,
weight: Optional[float] = None,
enrollment_date: Optional[Union[date, str]] = None,
class_name: Optional[str] = None,
major: str = None):
self.name = name
self.id_card = id_card
self.stu_id = stu_id
self.gender = gender
self.height = height
self.weight = weight
if isinstance(enrollment_date, str):
self.enrollment_date = date.fromisoformat(enrollment_date)
else:
self.enrollment_date = enrollment_date
self.class_name = class_name
self.major = major
self.age, self.birthday = self._calculate_age_and_birthday()
self._validation_errors = []
self._validate_all()
def _calculate_age_and_birthday(self):
birth_year = int(self.id_card[6:10])
birth_month = int(self.id_card[10:12])
birth_day = int(self.id_card[12:14])
birthday = date(birth_year, birth_month, birth_day)
today = date.today()
age = today.year - birth_year
if (today.month, today.day) < (birth_month, birth_day):
age -= 1
return age, birthday
def _validate_all(self):
self._validate_id_card()
self._validate_stu_id()
self._validate_name()
self._validate_enrollment_date()
self._validate_height()
self._validate_weight()
def _validate_id_card(self):
if len(self.id_card) != 18:
self._validation_errors.append("身份证号必须为18位")
# 简单的校验位验证,可根据国家标准完善
try:
int(self.id_card[:17])
except ValueError:
self._validation_errors.append("身份证号前17位必须为数字")
def _validate_stu_id(self):
if not self.stu_id:
self._validation_errors.append("学号不能为空")
def _validate_name(self):
if not (2 <= len(self.name) <= 20):
self._validation_errors.append("姓名长度需在2-20个字符之间")
if any(char.isdigit() or not char.isalpha() for char in self.name):
self._validation_errors.append("姓名不能包含数字和特殊符号")
def _validate_enrollment_date(self):
if self.enrollment_date and self.enrollment_date < self.birthday:
self._validation_errors.append("入学日期不能早于出生日期")
def _validate_height(self):
if self.height is not None and not (50 <= self.height <= 250):
self._validation_errors.append("身高需在50-250cm之间")
def _validate_weight(self):
if self.weight is not None and not (5 <= self.weight <= 300):
self._validation_errors.append("体重需在5-300kg之间")
@property
def is_valid(self):
return len(self._validation_errors) == 0
def get_errors(self):
return self._validation_errors.copy()
def to_dict(self):
return {
'name': self.name,
'id_card': self.id_card,
'stu_id': self.stu_id,
'gender': self.gender,
'height': self.height,
'weight': self.weight,
'enrollment_date': self.enrollment_date.isoformat() if self.enrollment_date else None,
'class_name': self.class_name,
'major': self.major,
'age': self.age,
'birthday': self.birthday.isoformat()
}
@classmethod
def from_dict(cls, data):
return cls(
name=data['name'],
id_card=data['id_card'],
stu_id=data['stu_id'],
gender=data['gender'],
height=data['height'],
weight=data['weight'],
enrollment_date=data['enrollment_date'],
class_name=data['class_name'],
major=data['major']
)
# 数据访问层接口
class IStudentDAL(ABC):
@abstractmethod
def get_by_id(self, id_card: str) -> Optional[Student]:
pass
@abstractmethod
def get_by_stu_id(self, stu_id: str) -> Optional[Student]:
pass
@abstractmethod
def get_all(self) -> List[Student]:
pass
@abstractmethod
def add(self, student: Student) -> bool:
pass
@abstractmethod
def delete(self, id_card: str = None, stu_id: str = None) -> bool:
pass
@abstractmethod
def update(self, student: Student) -> bool:
pass
# CSV数据访问层实现
class CSVStudentDAL(IStudentDAL):
def __init__(self, file_path):
self.file_path = file_path
if not os.path.exists(file_path):
with open(file_path, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=Student.from_dict({}).to_dict().keys())
writer.writeheader()
def get_by_id(self, id_card: str) -> Optional[Student]:
with open(self.file_path, 'r', newline='') as f:
reader = csv.DictReader(f)
for row in reader:
if row['id_card'] == id_card:
return Student.from_dict(row)
return None
def get_by_stu_id(self, stu_id: str) -> Optional[Student]:
with open(self.file_path, 'r', newline='') as f:
reader = csv.DictReader(f)
for row in reader:
if row['stu_id'] == stu_id:
return Student.from_dict(row)
return None
def get_all(self) -> List[Student]:
students = []
with open(self.file_path, 'r', newline='') as f:
reader = csv.DictReader(f)
for row in reader:
students.append(Student.from_dict(row))
return students
def add(self, student: Student) -> bool:
if self.get_by_id(student.id_card) or self.get_by_stu_id(student.stu_id):
return False
with open(self.file_path, 'a', newline='') as f:
writer = csv.DictWriter(f, fieldnames=student.to_dict().keys())
writer.writerow(student.to_dict())
return True
def delete(self, id_card: str = None, stu_id: str = None) -> bool:
students = self.get_all()
initial_length = len(students)
if id_card:
students = [s for s in students if s.id_card != id_card]
elif stu_id:
students = [s for s in students if s.stu_id != stu_id]
if len(students) < initial_length:
with open(self.file_path, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=students[0].to_dict().keys() if students else [])
writer.writeheader()
for s in students:
writer.writerow(s.to_dict())
return True
return False
def update(self, student: Student) -> bool:
students = self.get_all()
for i, s in enumerate(students):
if s.id_card == student.id_card or s.stu_id == student.stu_id:
students[i] = student
with open(self.file_path, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=students[0].to_dict().keys() if students else [])
writer.writeheader()
for s in students:
writer.writerow(s.to_dict())
return True
return False
# JSON数据访问层实现
class JSONStudentDAL(IStudentDAL):
def __init__(self, file_path):
self.file_path = file_path
if not os.path.exists(file_path):
with open(file_path, 'w') as f:
json.dump([], f)
def get_by_id(self, id_card: str) -> Optional[Student]:
with open(self.file_path, 'r') as f:
data = json.load(f)
for row in data:
if row['id_card'] == id_card:
return Student.from_dict(row)
return None
def get_by_stu_id(self, stu_id: str) -> Optional[Student]:
with open(self.file_path, 'r') as f:
data = json.load(f)
for row in data:
if row['stu_id'] == stu_id:
return Student.from_dict(row)
return None
def get_all(self) -> List[Student]:
with open(self.file_path, 'r') as f:
data = json.load(f)
return [Student.from_dict(row) for row in data]
def add(self, student: Student) -> bool:
if self.get_by_id(student.id_card) or self.get_by_stu_id(student.stu_id):
return False
with open(self.file_path, 'r') as f:
data = json.load(f)
data.append(student.to_dict())
with open(self.file_path, 'w') as f:
json.dump(data, f, indent=4)
return True
def delete(self, id_card: str = None, stu_id: str = None) -> bool:
with open(self.file_path, 'r') as f:
data = json.load(f)
initial_length = len(data)
if id_card:
data = [s for s in data if s['id_card'] != id_card]
elif stu_id:
data = [s for s in data if s['stu_id'] != stu_id]
if len(data) < initial_length:
with open(self.file_path, 'w') as f:
json.dump(data, f, indent=4)
return True
return False
def update(self, student: Student) -> bool:
with open(self.file_path, 'r') as f:
data = json.load(f)
for i, s in enumerate(data):
if s['id_card'] == student.id_card or s['stu_id'] == student.stu_id:
data[i] = student.to_dict()
with open(self.file_path, 'w') as f:
json.dump(data, f, indent=4)
return True
return False
# SQLite数据访问层实现
class SQLiteStudentDAL(IStudentDAL):
def __init__(self, db_path):
self.db_path = db_path
self._create_table()
def _create_table(self):
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS students (
id_card TEXT PRIMARY KEY,
stu_id TEXT UNIQUE,
name TEXT,
gender BOOLEAN,
height INTEGER,
weight REAL,
enrollment_date TEXT,
class_name TEXT,
major TEXT,
age INTEGER,
birthday TEXT
)
''')
conn.commit()
conn.close()
def get_by_id(self, id_card: str) -> Optional[Student]:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("SELECT * FROM students WHERE id_card =?", (id_card,))
row = cursor.fetchone()
conn.close()
if row:
data = dict(zip([description[0] for description in cursor.description], row))
return Student.from_dict(data)
return None
def get_by_stu_id(self, stu_id: str) -> Optional[Student]:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("SELECT * FROM students WHERE stu_id =?", (stu_id,))
row = cursor.fetchone()
conn.close()
if row:
data = dict(zip([description[0] for description in cursor.description], row))
return Student.from_dict(data)
return None
def get_all(self) -> List[Student]:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("SELECT * FROM students")
rows = cursor.fetchall()
conn.close()
return [Student.from_dict(dict(zip([description[0] for description in cursor.description], row))) for row in
rows]
def add(self, student: Student) -> bool:
if self.get_by_id(student.id_card) or self.get_by_stu_id(student.stu_id):
return False
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
try:
cursor.execute('''
INSERT INTO students (id_card, stu_id, name, gender, height, weight, enrollment_date, class_name, major, age, birthday)
VALUES (?,?,?,?,?,?,?,?,?,?,?)
''', (
student.id_card, student.stu_id, student.name, student.gender, student.height, student.weight,
student.enrollment_date.isoformat() if student.enrollment_date else None, student.class_name,
student.major, student.age, student.birthday.isoformat()))
conn.commit()
return True
except sqlite3.IntegrityError:
return False
finally:
conn.close()
def delete(self, id_card: str = None, stu_id: str = None) -> bool:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
if id_card:
cursor.execute("DELETE FROM students WHERE id_card =?", (id_card,))
elif stu_id:
cursor.execute("DELETE FROM students WHERE stu_id =?", (stu_id,))
rows_affected = cursor.rowcount
conn.commit()
conn.close()
return rows_affected > 0
def update(self, student: Student) -> bool:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
try:
cursor.execute('''
UPDATE students
SET stu_id =?, name =?, gender =?, height =?, weight =?, enrollment_date =?, class_name =?, major =?, age =?, birthday =?
WHERE id_card =?
''', (
student.stu_id, student.name, student.gender, student.height, student.weight,
student.enrollment_date.isoformat() if student.enrollment_date else None, student.class_name,
student.major, student.age, student.birthday.isoformat(), student.id_card))
rows_affected = cursor.rowcount
conn.commit()
return rows_affected > 0
except sqlite3.IntegrityError:
return False
finally:
conn.close()
# 业务逻辑层
class StudentBLL:
def __init__(self, dal: IStudentDAL):
self.dal = dal
def add_student(self, student: Student) -> bool:
if not student.is_valid:
raise ValueError(f"学生数据无效: {', '.join(student.get_errors())}")
return self.dal.add(student)
def delete_student(self, id_card: str = None, stu_id: str = None) -> bool:
return self.dal.delete(id_card, stu_id)
def update_student(self, student: Student) -> bool:
if not student.is_valid:
raise ValueError(f"学生数据无效: {', '.join(student.get_errors())}")
return self.dal.update(student)
def get_student_by_id(self, id_card: str) -> Optional[Student]:
return self.dal.get_by_id(id_card)
def get_student_by_stu_id(self, stu_id: str) -> Optional[Student]:
return self.dal.get_by_stu_id(stu_id)
def get_all_students(self) -> List[Student]:
return self.dal.get_all()
def query_by_name(self, name: str) -> List[Student]:
return [s for s in self.get_all_students() if name.lower() in s.name.lower()]
def query_by_class(self, class_name: str) -> List[Student]:
return [s for s in self.get_all_students() if class_name.lower() in s.class_name.lower()]
def query_by_major(self, major: str) -> List[Student]:
return [s for s in self.get_all_students() if major.lower() in s.major.lower()]
def get_student_count(self) -> int:
return len(self.get_all_students())
def get_major_count(self) -> dict:
major_count = {}
for student in self.get_all_students():
if student.major in major_count:
major_count[student.major] += 1
else:
major_count[student.major] = 1
return major_count
def get_avg_height_by_class(self, class_name: str) -> float:
students = [s for s in self.get_all_students() if s.class_name == class_name and s.height is not None]
if not students:
return 0
return sum(s.height for s in students) / len(students)
def get_avg_weight_by_class(self, class_name: str) -> float:
students = [s for s in self.get_all_students() if s.class_name == class_name and s.weight is not None]
if not students:
return 0
return sum(s.weight for s in students) / len(students)
def get_avg_height_by_major(self, major: str) -> float:
students = [s for s in self.get_all_students() if s.major == major and s.height is not None]
if not students:
return 0
return sum(s.height for s in students) / len(students)
def get_avg_weight_by_major(self, major: str) -> float:
students = [s for s in self.get_all_students() if s.major == major and s.weight is not None]
if not students:
return 0
return sum(s.weight for s in students) / len(students)
def import_from_csv(self, file_path):
with open(file_path, 'r', newline='') as f:
reader = csv.DictReader(f)
for row in reader:
student = Student.from_dict(row)
if student.is_valid:
self.add_student(student)
def import_from_json(self, file_path):
with open(file_path, 'r') as f:
data = json.load(f)
for row in data:
student = Student.from_dict(row)
if student.is_valid:
self.add_student(student)
def export_to_csv(self, file_path):
students = self.get_all_students()
with open(file_path, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=students[0].to_dict().keys() if students else [])
writer.writeheader()
for s in students:
writer.writerow(s.to_dict())
def export_to_json(self, file_path):
students = self.get_all_students()
with open(file_path, 'w') as f:
json.dump([s.to_dict() for s in students], f, indent=4)
# 用户界面层
class StudentUI:
def __init__(self, bll: StudentBLL):
self.bll = bll
def display_menu(self):
print("\n===== 学生信息管理系统 =====")
print("1. 添加学生信息")
print("2. 删除学生信息")
print("3. 修改学生信息")
print("4. 查看学生详细信息")
print("5. 查询学生信息")
print("6. 统计信息")
print("7. 数据导入")
print("8. 数据导出")
print("0. 退出系统")
print("==========================")
def display_query_menu(self):
print("\n===== 查询学生信息 =====")
print("1. 按学号查询")
print("2. 按姓名查询")
print("3. 按班级查询")
print("4. 按专业查询")
print("5. 返回上一级")
print("======================")
def display_stats_menu(self):
print("\n===== 统计信息 =====")
print("1. 学生总数")
print("2. 各专业学生人数")
print("3. 按班级计算平均身高")
print("4. 按班级计算平均体重")
print("5. 按专业计算平均身高")
print("6. 按专业计算平均体重")
print("7. 返回上一级")
print("====================")
def display_import_menu(self):
print("\n===== 数据导入 =====")
print("1. 从CSV导入")
print("2. 从JSON导入")
print("3. 返回上一级")
print("====================")
def display_export_menu(self):
print("\n===== 数据导出 =====")
print("1. 导出到CSV")
print("2. 导出到JSON")
print("3. 返回上一级")
print("====================")
def get_student_input(self, existing_student=None):
"""获取学生输入,支持使用现有学生数据作为默认值"""
if existing_student:
print(f"当前值: {existing_student.name}")
name = input("请输入姓名 (直接回车保持不变): ") or (existing_student.name if existing_student else "")
if existing_student:
print(f"当前值: {existing_student.id_card}")
id_card = input("请输入身份证号 (直接回车保持不变): ") or (existing_student.id_card if existing_student else "")
if existing_student:
print(f"当前值: {existing_student.stu_id}")
stu_id = input("请输入学号 (直接回车保持不变): ") or (existing_student.stu_id if existing_student else "")
if existing_student and existing_student.gender is not None:
print(f"当前值: {existing_student.gender}")
gender_str = input("请输入性别 (True/False直接回车保持不变): ")
gender = None
if gender_str:
gender = gender_str.lower() == 'true'
elif existing_student:
gender = existing_student.gender
if existing_student and existing_student.height is not None:
print(f"当前值: {existing_student.height}")
height_str = input("请输入身高 (cm直接回车保持不变): ")
height = None
if height_str:
height = int(height_str)
elif existing_student:
height = existing_student.height
if existing_student and existing_student.weight is not None:
print(f"当前值: {existing_student.weight}")
weight_str = input("请输入体重 (kg直接回车保持不变): ")
weight = None
if weight_str:
weight = float(weight_str)
elif existing_student:
weight = existing_student.weight
if existing_student and existing_student.enrollment_date:
print(f"当前值: {existing_student.enrollment_date.isoformat()}")
enrollment_date = input("请输入入学日期 (YYYY-MM-DD直接回车保持不变): ") or (
existing_student.enrollment_date.isoformat() if existing_student and existing_student.enrollment_date else None
)
if existing_student:
print(f"当前值: {existing_student.class_name}")
class_name = input("请输入班级名称 (直接回车保持不变): ") or (
existing_student.class_name if existing_student else "")
if existing_student:
print(f"当前值: {existing_student.major}")
major = input("请输入专业 (直接回车保持不变): ") or (existing_student.major if existing_student else "")
return Student(name, id_card, stu_id, gender, height, weight, enrollment_date, class_name, major)
def run(self):
while True:
self.display_menu()
choice = input("请选择操作: ")
if choice == "1":
self.add_student()
elif choice == "2":
self.delete_student()
elif choice == "3":
self.update_student()
elif choice == "4":
self.view_student_details()
elif choice == "5":
self.query_student()
elif choice == "6":
self.statistics()
elif choice == "7":
self.import_data()
elif choice == "8":
self.export_data()
elif choice == "0":
print("感谢使用,再见!")
break
else:
print("无效选择,请重试!")
def add_student(self):
print("\n===== 添加学生信息 =====")
try:
student = self.get_student_input()
if self.bll.add_student(student):
print("添加成功!")
else:
print("添加失败,学号或身份证号可能已存在。")
except ValueError as e:
print(f"添加失败: {e}")
def delete_student(self):
print("\n===== 删除学生信息 =====")
choice = input("按学号删除请输入1按身份证号删除请输入2: ")
if choice == "1":
stu_id = input("请输入要删除的学号: ")
if self.bll.delete_student(stu_id=stu_id):
print("删除成功!")
else:
print("删除失败,学号不存在。")
elif choice == "2":
id_card = input("请输入要删除的身份证号: ")
if self.bll.delete_student(id_card=id_card):
print("删除成功!")
else:
print("删除失败,身份证号不存在。")
else:
print("无效选择,请重试!")
def update_student(self):
print("\n===== 修改学生信息 =====")
stu_id = input("请输入要修改的学生学号: ")
student = self.bll.get_student_by_stu_id(stu_id)
if not student:
print("学号不存在。")
return
print(f"当前信息: {student.to_dict()}")
print("(直接回车表示不修改)")
# 使用现有的学生数据作为默认值
new_student = self.get_student_input(student)
# 确保不修改ID和学号
new_student.id_card = student.id_card
new_student.stu_id = student.stu_id
try:
if self.bll.update_student(new_student):
print("修改成功!")
else:
print("修改失败,可能是数据验证不通过。")
except ValueError as e:
print(f"修改失败: {e}")
def view_student_details(self):
print("\n===== 查看学生详细信息 =====")
stu_id = input("请输入要查看的学生学号: ")
student = self.bll.get_student_by_stu_id(stu_id)
if student:
print(student.to_dict())
else:
print("学号不存在。")
def query_student(self):
while True:
self.display_query_menu()
choice = input("请选择查询方式: ")
if choice == "1":
stu_id = input("请输入学号: ")
student = self.bll.get_student_by_stu_id(stu_id)
if student:
print(student.to_dict())
else:
print("未找到该学生。")
elif choice == "2":
name = input("请输入姓名: ")
students = self.bll.query_by_name(name)
if students:
for s in students:
print(s.to_dict())
else:
print("未找到匹配的学生。")
elif choice == "3":
class_name = input("请输入班级名称: ")
students = self.bll.query_by_class(class_name)
if students:
for s in students:
print(s.to_dict())
else:
print("未找到匹配的学生。")
elif choice == "4":
major = input("请输入专业名称: ")
students = self.bll.query_by_major(major)
if students:
for s in students:
print(s.to_dict())
else:
print("未找到匹配的学生。")
elif choice == "5":
break
else:
print("无效选择,请重试!")
def statistics(self):
while True:
self.display_stats_menu()
choice = input("请选择统计方式: ")
if choice == "1":
print(f"学生总数: {self.bll.get_student_count()}")
elif choice == "2":
major_count = self.bll.get_major_count()
for major, count in major_count.items():
print(f"{major}: {count}")
elif choice == "3":
class_name = input("请输入班级名称: ")
avg_height = self.bll.get_avg_height_by_class(class_name)
print(f"{class_name} 班级平均身高: {avg_height:.2f} cm")
elif choice == "4":
class_name = input("请输入班级名称: ")
avg_weight = self.bll.get_avg_weight_by_class(class_name)
print(f"{class_name} 班级平均体重: {avg_weight:.2f} kg")
elif choice == "5":
major = input("请输入专业名称: ")
avg_height = self.bll.get_avg_height_by_major(major)
print(f"{major} 专业平均身高: {avg_height:.2f} cm")
elif choice == "6":
major = input("请输入专业名称: ")
avg_weight = self.bll.get_avg_weight_by_major(major)
print(f"{major} 专业平均体重: {avg_weight:.2f} kg")
elif choice == "7":
break
else:
print("无效选择,请重试!")
def import_data(self):
while True:
self.display_import_menu()
choice = input("请选择导入方式: ")
if choice == "1":
file_path = input("请输入CSV文件路径: ")
try:
self.bll.import_from_csv(file_path)
print("导入成功!")
except Exception as e:
print(f"导入失败: {e}")
elif choice == "2":
file_path = input("请输入JSON文件路径: ")
try:
self.bll.import_from_json(file_path)
print("导入成功!")
except Exception as e:
print(f"导入失败: {e}")
elif choice == "3":
break
else:
print("无效选择,请重试!")
def export_data(self):
while True:
self.display_export_menu()
choice = input("请选择导出方式: ")
if choice == "1":
file_path = input("请输入导出的CSV文件路径: ")
try:
self.bll.export_to_csv(file_path)
print("导出成功!")
except Exception as e:
print(f"导出失败: {e}")
elif choice == "2":
file_path = input("请输入导出的JSON文件路径: ")
try:
self.bll.export_to_json(file_path)
print("导出成功!")
except Exception as e:
print(f"导出失败: {e}")
elif choice == "3":
break
else:
print("无效选择,请重试!")
if __name__ == "__main__":
# 选择数据存储方式
storage_choice = input("请选择数据存储方式 (1: CSV, 2: JSON, 3: SQLite): ")
if storage_choice == "1":
dal = CSVStudentDAL("students.csv")
elif storage_choice == "2":
dal = JSONStudentDAL("students.json")
elif storage_choice == "3":
dal = SQLiteStudentDAL("students.db")
else:
print("无效选择默认使用SQLite。")
dal = SQLiteStudentDAL("students.db")
bll = StudentBLL(dal)
ui = StudentUI(bll)
print("欢迎使用学生信息管理系统!")
ui.run()
Loading…
Cancel
Save