项目需求:
利用规范化目录结构完成一个学生选课系统。
-
**角色:**学生、管理员。
-
功能分析:
- 用户登录之后就可以直接判断用户身份,是学生还是管理员。
- 学生登录之后有以下几个功能:
- 查看所有课程。
- 选择课程。
- 查看所选课程。
- 退出程序。
- 管理员登录之后有以下几个功能:
- 创建课程(需要记录日志)。
- 创建学生账号(需要记录日志)。
- 查看所有课程。
- 查看所有学生。
- 查看所有学生的选课情况。
- 退出程序。
-
课程属性:课程名,价格,周期,老师。
-
学生属性:姓名,所选课程。
-
管理员属性:姓名。
流程图: https://www.processon.com/view/link/5d283960e4b0878e40af9dd8
目录结构:
具体代码:
start.py
import sys import os BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) from core import src from core.src import Course from core.src import Student if __name__ == \'__main__\': src.main()
settings.py
import os import logging BASE_DIR = os.path.dirname(os.path.dirname(__file__)) USERINFO_PATH = os.path.join(BASE_DIR, \'db\',\'user_info\') COURSE_PATH = os.path.join(BASE_DIR, \'db\',\'Course\') STUDENT_PATH = os.path.join(BASE_DIR, \'db\',\'Student\') LOGGING_PATH = os.path.join(BASE_DIR, \'log\',\'admin.log\') SIMPLE_FORMAT = \'[%(asctime)s] %(message)s\' LOGGING_DIC = { \'version\': 1, \'disable_existing_loggers\': False, \'formatters\': { \'simple\': { \'format\': SIMPLE_FORMAT, }, }, \'filters\': {}, \'handlers\': { # 打印到终端的日志 \'stream\': { \'level\': \'DEBUG\', \'class\': \'logging.StreamHandler\', # 打印到屏幕 \'formatter\': \'simple\' }, # 打印到文件的日志,收集info及以上的日志 \'file\': { \'level\': \'DEBUG\', \'class\': \'logging.handlers.RotatingFileHandler\', # 保存到文件 \'formatter\': \'simple\', \'filename\': LOGGING_PATH, # 日志文件 \'maxBytes\': 1024 * 1024 * 5, # 日志大小 5M \'backupCount\': 5, \'encoding\': \'utf-8\', # 日志文件的编码,再也不用担心中文log乱码了 }, }, \'loggers\': { # logging.getLogger(__name__)拿到的logger配置 \'\': { \'handlers\': [\'stream\', \'file\'], \'level\': \'DEBUG\', \'propagate\': True, }, }, }
src.py
import os import sys import pickle from conf import settings from lib import common class Base: def show_courses(self): with open(settings.COURSE_PATH, mode="rb") as f: num = 0 while 1: try: num += 1 obj = pickle.load(f) print(f"{num}: {obj.name} {obj.price} {obj.period}") except EOFError: break def exit(self): sys.exit(f"\033[0;32m感谢{self.name}使用选课系统!\033[0m") class Student(Base): operate_lst = [ ("查看可选课程", "show_courses"), ("选择课程", "select_course"), ("查看所选课程", "show_selected_course"), ("退出", "exit") ] def __init__(self, name): self.name = name self.courses = [] def select_course(self): self.show_courses() try: chice_num = input("\033[0;32m请输入要选择的课程序号:\033[0m").strip() with open(settings.COURSE_PATH, mode="rb") as f: for i in range(int(chice_num)): obj = pickle.load(f) self.courses.append(obj) print(f"\033[0;32m您已经成功添加了{obj.name}课程\033[0m") except Exception: print("输入有误") def show_selected_course(self): print(f"\033[0;32m您已报名如下课程\033[0m") for obj_course in self.courses: print(f"\033[0;32m课程名:{obj_course.name},课程价格:{obj_course.price} 课程周期:{obj_course.period}\033[0m") def exit(self): with open(settings.STUDENT_PATH, mode="rb") as f1,\ open(f"{settings.STUDENT_PATH}_bak", mode="wb") as f2: while 1: try: obj = pickle.load(f1) pickle.dump(self if obj.name == self.name else obj, f2) except EOFError: break os.remove(settings.STUDENT_PATH) os.rename(f"{settings.STUDENT_PATH}_bak", settings.STUDENT_PATH) super().exit() @classmethod def get_obj(cls, username): with open(settings.STUDENT_PATH, mode="rb") as f1: while 1: try: obj = pickle.load(f1) if username == obj.name: return obj except EOFError: break class Manager(Base): operate_lst = [ ("创建课程", "create_course"), ("创建学生", "create_student"), ("查看可选课程", "show_courses"), ("查看所有学生", "show_students"), ("查看所有学生选课情况", "show_students_courses"), ("退出", "exit") ] def __init__(self, name): self.name = name def create_course(self): course = getattr(sys.modules[__name__], "Course") name, price, period = input("请依次输入课程名,价格以及课程周期,以|分割").strip().split("|") obj = course(name, price, period) with open(settings.COURSE_PATH, mode="ab") as f1: pickle.dump(obj, f1) logger = common.record_logger() logger.info(f"成功创建{name}课程") def create_student(self): student_username = input("\033[0;32m 请输入学生姓名:\033[0m").strip() student_password = input("\033[0;32m 请输入学生密码:\033[0m").strip() student_pwd_md5 = common.hashlib_md5(student_password) with open(settings.USERINFO_PATH, encoding="utf-8", mode="a") as f1: f1.write(f"\n{student_username}|{student_pwd_md5}|Student") with open(settings.STUDENT_PATH, mode="ab") as f: obj = getattr(sys.modules[__name__], "Student")(student_username) pickle.dump(obj, f) logger = common.record_logger() logger.info(f"您已成功创建学生账号:{student_username},初始密码:{student_password}") def show_students(self): with open(settings.STUDENT_PATH, mode="rb") as f1: while 1: try: obj = pickle.load(f1) print(obj.name) except EOFError: break def show_students_courses(self): """查看所有学生选课情况""" with open(settings.STUDENT_PATH, mode=\'rb\') as f1: while 1: try: obj = pickle.load(f1) print(f\'\033[0;32m学生:{obj.name},所选课程:\ {["%s-%s-%s" %(course.name,course.price,course.period) for course in obj.courses]}\033[0m\') except EOFError: break def exit(self): super().exit() @classmethod def get_obj(cls, username): return Manager(username) class Course: def __init__(self, name, price, period): self.name = name self.price = price self.period = period self.teacher = None def login(): count = 1 while count < 4: username = input("请输入用户名: ").strip() password = input("请输入密码: ").strip() pwd_md5 = common.hashlib_md5(password) with open(settings.USERINFO_PATH, encoding="utf-8") as f1: for line in f1: if not line.strip():continue user, pwd, identify = line.strip().split("|") if user == username and pwd == pwd_md5: return {"username": user, "identify": identify, "auth": True} else: print("用户名或密码错误,请重新输入") count += 1 return {"username": username, "identify": None, "auth": False} def main(): print("\033[0;32m欢迎访问选课系统,请先登录\033[0m") dict_auth = login() print(f"\033[0;32m登陆成功,欢迎{dict_auth[\'username\']},您的身份是{dict_auth[\'identify\']}\033[0m") if dict_auth["auth"]: if hasattr(sys.modules[__name__], dict_auth["identify"]): cls = getattr(sys.modules[__name__], dict_auth["identify"]) obj = cls.get_obj(dict_auth["username"]) while 1: for num, option in enumerate(cls.operate_lst, 0): print(f"{num+1}: {option[0]}") choice_num = int(input(\'\033[0;32m 请输入选项:\033[0m\').strip()) getattr(obj, cls.operate_lst[choice_num - 1][1])() else: print("三次验证失败,系统自动退出") return False
common.py
import hashlib import logging.config from conf.settings import LOGGING_DIC def hashlib_md5(password): ret = hashlib.md5() ret.update(password.encode("utf-8")) return ret.hexdigest() def record_logger(): logging.config.dictConfig(LOGGING_DIC) logger = logging.getLogger() return logger