Day7作业:选课系统
这周的作业有点糙,迁就看吧,给大家点思路:
readme:
需要安装模块: prettytable 测试帐号: 1.后台管理:admin/admin 只设定了这个后台管理帐号,没有写到数据库中 2.学生选课系统需要先注册才可登录操作,测试帐号cc/123,也可注册新帐号使用 设计思路: 1.使用pickle存储数据,数据类型为老师,学生,课程的对象 2.使用流程为:创建老师-->创建课程,并关联老师-->学生注册并登录-->学生选课,上课等操作 3.老师资产的变化是由学生选择上课或者课程事故触发的,管理员没有权限操作 4.教师名是唯一的,作为数据标识ID 本课难点: 1.整体比较简单,难点在于上个数据库中的数据关联性. 2.由于同一对象存到不同数据库中后,反序列化取出的值是不一样的,简要说明就是对象保存后不是引用关系 3.所以在保存对象时,对象属性中标记了教师名称,课程名称作为引用ID来做相关数据的匹配
流程图:
目录介绍:
目录说明: |____bin 执行目录,程序入口 | |____init_all_data.py 初始化数据库 | |____manage.py 管理员入口 | |____student.py 学生入口 |____conf 配置文件目录 | |____setting.py 配置文件 |____core 主程序目录 | |____manage_sys.py 管理主程序 | |____student.py 学生主程序 |____data 数据库目录 | |____manage.pickle 教师对象数据 | |____student.pickle 学生对象数据 | |____subject.pickle 课程对象数据
代码:
bin/init_all_data:
#!/usr/bin/env python # -*-coding=utf-8-*- # Auther:ccorz Mail:ccniubi@163.com Blog:http://www.cnblogs.com/ccorz/ # GitHub:https://github.com/ccorzorz import sys,os,pickle BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) # print(BASE_DIR) from conf.setting import * from core import manage_sys from core import student """ 系统数据初始化程序,慎重使用!!!!! """ #将所有pickle数据库中的数据写入空列表 manage_sys.data_flush([]) manage_sys.subject_data_flush([]) student.student_data_flush([])
bin/manage.py
#!/usr/bin/env python # -*-coding=utf-8-*- # Auther:ccorz Mail:ccniubi@163.com Blog:http://www.cnblogs.com/ccorz/ # GitHub:https://github.com/ccorzorz import sys,os BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) import core.manage_sys """ 管理员后台入口,测试帐号admin/admin """ if __name__ == '__main__': core.manage_sys.login() core.manage_sys.main()
bin/student.py
#!/usr/bin/env python # -*-coding=utf-8-*- # Auther:ccorz Mail:ccniubi@163.com Blog:http://www.cnblogs.com/ccorz/ # GitHub:https://github.com/ccorzorz import sys,os BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) import core.student """ 学生系统入口,可注册登录,或者测试帐号cc/123 """ if __name__ == '__main__': core.student.main()
conf/setting.py:
#!/usr/bin/env python # -*-coding=utf-8-*- # Auther:ccorz Mail:ccniubi@163.com Blog:http://www.cnblogs.com/ccorz/ # GitHub:https://github.com/ccorzorz import os,sys,time BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) """ 配置文件 """ #存储老师信息的数据文件 manage_data_file='%s/data/manage.pickle'%BASE_DIR #存储课程信息的数据文件 subject_data_file='%s/data/subject.pickle'%BASE_DIR #存储学生信息的数据文件 student_data_file='%s/data/student.pickle'%BASE_DIR #定义教师类 class Teacher: def __init__(self,name,age,favor): self.favor=favor self.name=name self.age=age self.asset=0 def gain(self,value): """ 上课时老师资产增加 :param value: 课程的课时费 :return: """ self.asset=int(self.asset)+int(value) def teach_accidents(self): """ 课程事故时老师资产减少 :return: """ self.asset-=1 from core import manage_sys #定义课程类 class Subject: def __init__(self,classes,value,teacher_name):#构造方法 self.classes=classes self.value=int(value) self.teacher_name=teacher_name def attend_class(self): """ 课程上课,并对相应老师的资产做相应调整 :return: """ print('来上课,今天我们学%s'%self.classes) print(5*('%s...'%self.classes)) time.sleep(1) print('齐活!下课下课!!!') teacher_obj,index=manage_sys.sub_match_teacher(self.classes) #执行老师对象的资产增加方法 teacher_obj.gain(self.value) teacher_data=manage_sys.data_read() teacher_data[index]=teacher_obj manage_sys.data_flush(teacher_data) def accidents(self): """ 课堂事故,并对相应老师的资产做相应调整, :return: """ print('卧槽,今天上不了课了,%s老师去做大保健了'%self.teacher_name) print(5*'大保健...') time.sleep(1) print('退钱退钱退钱!!!') teacher_obj,index=manage_sys.sub_match_teacher(self.classes) #执行老师对象的资产减少方法 teacher_obj.teach_accidents() teacher_data=manage_sys.data_read() teacher_data[index]=teacher_obj manage_sys.data_flush(teacher_data) #定义学生的类 class Student: def __init__(self,name,pwd): self.name=name self.pwd=pwd self.subject_classes=[]
core/manage_sys.py
#!/usr/bin/env python # -*-coding=utf-8-*- # Auther:ccorz Mail:ccniubi@163.com Blog:http://www.cnblogs.com/ccorz/ # GitHub:https://github.com/ccorzorz import sys,os,pickle,prettytable,time BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from conf.setting import * #定义登录状态的常量 LOGIN_STATE=False def check_login(func): """ 装饰器,判断管理员权限 :param func: :return: """ def inner(*args,**kwargs): if LOGIN_STATE: #判断是否已登录 res=func(*args,**kwargs) return res else:print('程序需要登录后才可执行!') return inner def data_read(): """ 老师DB读取函数 :return: 读取结果 """ data=pickle.load(open(manage_data_file,'rb')) return data def data_flush(args): """ 写入修改后的新教师类数据 :param args: 修改后的老师数据 :return: """ pickle.dump(args,open(manage_data_file,'wb')) def subject_data_read(): """ 读取课程类的数据 :return: 读取结果 """ subject_data=pickle.load(open(subject_data_file,'rb')) return subject_data def subject_data_flush(args): """ 写入修改后的课程类数据 :param args: 修改后的数据 :return: """ pickle.dump(args,open(subject_data_file,'wb')) def sub_match_teacher(sub_classes): """ 匹配课程类中的老师名称与老师类数据中的老师对象 :param sub_classes:课程名称 :return:匹配到的老师对象以及对应的索引 """ #读取课程数据 subject_data=subject_data_read() #遍历课程数据,查找到课堂的名称 for item in subject_data: if sub_classes==item.classes: teac_name=item.teacher_name #遍历教师数据,查找到对应老师的对象以及下标值 teacher_data=data_read() for item in teacher_data: if item.name==teac_name: teacher_ob=item index=teacher_data.index(item) return teacher_ob,index def teacher_name(): """ 生成教师名字列表函数 :return: 返回名字列表 """ manage_data=data_read() teacher_list=[] for teacher in manage_data: teacher_list.append(teacher.name) # print(teacher_list) return teacher_list def subject_name(): """ 生成课程名称列表函数 :return: 课程名称列表 """ subject_data=subject_data_read() subject_list=[] for subject in subject_data: subject_list.append(subject.classes) # print(subject_list) return subject_list @check_login def creat_teacher(): """ 创建教师函数 :return: """ #读取教书数据 manage_data=data_read() teacher_list=teacher_name() name=input('输入教师姓名:') if name in teacher_list: #判断是否已存在此教师 print('已有教师:%s的数据'%name) else: while True: age=input('请输入教师年龄:') if age.isdigit(): age=int(age) break else:print('输入有误,请重新输入') favor=input('请输入教师爱好和擅长,可多选,使用逗号隔开:') #调用教师类创建教师,并赋予相应属性 docor_name=Teacher(name,age,favor) manage_data.append(docor_name) data_flush(manage_data) print('教师%s已创建成功!'%name) @check_login def creat_subject(): """ 创建课程函数 :return: """ #读取课程数据 subject_data=subject_data_read() subject_list=subject_name() classes=input('请输入课程名称:') #判断是否有此课程 if classes in subject_list: print('已经有%s课程'%classes) else: while True: value=input('请输入课时费:') if value.isdigit(): value=int(value) break else:print('输入有误,请重新输入.') while True: print('请选择授课老师'.center(50,'*')) manage_data=show_teachers() num=input('请选择老师对应的序列号') if num.isdigit(): num=int(num) if num < len(manage_data): teacher_name=manage_data[num].name #调用课程类创建课程,并赋予相应属性 subject_obj=Subject(classes,value,teacher_name) subject_data.append(subject_obj) subject_data_flush(subject_data) break else:print('输入有误,请重新输入.') else:print('输入有误,请重新输入.') # @check_login def show_teachers(): """ 显示所有教师信息函数 :return: """ #遍历教师数据文件,并打印对应信息 manage_data=data_read() row=prettytable.PrettyTable() row.field_names=['序列号','教师姓名','年龄','爱好','目前资产'] for teach in manage_data: row.add_row([manage_data.index(teach), teach.name, teach.age, teach.favor, teach.asset]) print(row) return manage_data def show_subject(): """ 显示所有课程信息 :return: """ #遍历课程数据,并显示相应信息 subject_data=subject_data_read() row=prettytable.PrettyTable() row.field_names=['序列号','学科名','课时费','授课老师',] for subject in subject_data: row.add_row([subject_data.index(subject), subject.classes, subject.value, subject.teacher_name]) print(row) return subject_data def logout(): """ 退出系统函数 :return: """ exit('程序退出!') def menu(): """ 打印菜单函数 :return: """ row=prettytable.PrettyTable() row.field_names=['创建老师','创建课程','查看所有老师','查看所有课程','退出程序'] row.add_row([0,1,2,3,'q&quit']) print(row) def login(): """ 登录函数 :return: """ user=input('请输入管理员用户名:') pwd=input('请输入密码:') if (user and pwd) == 'admin': #登录成功后修改全局变量 global LOGIN_STATE LOGIN_STATE=True print('登录成功!') return LOGIN_STATE else: print('用户名或者密码错误!') return False @check_login def main(): """ 主函数,系统入口 :return: """ while True: menu() #打印菜单后,将函数名形成列表让用户选择,选择后执行对应的函数 menu_list=[creat_teacher,creat_subject,show_teachers,show_subject,logout] inp=input('请选择操作对应的序列号:') if inp.isdigit(): inp=int(inp) if inp < len(menu_list): menu_list[inp]() time.sleep(1) elif inp == 'q' or inp =='quit': logout() else:print('输入错误,请重新输入.')
core/student.py:
#!/usr/bin/env python # -*-coding=utf-8-*- # Auther:ccorz Mail:ccniubi@163.com Blog:http://www.cnblogs.com/ccorz/ # GitHub:https://github.com/ccorzorz import sys,os,pickle,prettytable BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from conf.setting import * from core import manage_sys # USER=None def student_data_read(): """ 读取学生数据 :return: 读取到的学生数据 """ student_data=pickle.load(open(student_data_file,'rb')) return student_data def student_data_flush(args): """ 刷新学生数据 :param args: 新的学生数据 :return: """ pickle.dump(args,open(student_data_file,'wb')) def student_name(): """ 生成学生登录用户名列表 :return: """ student_data=student_data_read() student_name_list=[] for item in student_data: student_name_list.append(item.name) return student_name_list def regist(): """ 注册函数 :return: """ student_data=student_data_read() student_name_list=student_name() name=input('请输入您的用户名:') if name in student_name_list: #判断是否存在用户名 print('已有用户:%s'%name) else: pwd=input('请输入您的密码:') for i in range(3): pwd_again=input('确认注册密码:') if pwd_again == pwd: print('%s注册成功!'%name) #调用学生类生成学生对象,并写入学生类数据库中 student_obj=Student(name,pwd) student_data.append(student_obj) student_data_flush(student_data) break else: print('密码不正确,请重新输入,还剩尝试次数%s'%(2-i)) def s_login(): """ 学生登录函数 :return: """ #读取学生类数据库和学生姓名列表,两个列表的下标相匹配 student_data=student_data_read() student_name_list=student_name() name=input('请输入您的用户名:') if name not in student_name_list: print('无%s用户名.'%name) else: for i in range(3): pwd=input('请输入用户%s的密码:'%name) #如果输入的密码与学生类中的密码匹配 if pwd==student_data[student_name_list.index(name)].pwd: global USER USER=name print('登录成功!!!') return True else:print('密码校验失败,剩余尝试次数:%s'%(2-i)) def choice_subject(): """ 选择课程函数 :return: """ #读取学生类数据库和学生姓名列表,两个列表的下标相匹配 student_data=student_data_read() student_name_list=student_name() #读取课程类数据库 subject_data=manage_sys.show_subject() inp = input('请选择学科名对应的序列号') if inp.isdigit(): inp=int(inp) if inp < len(subject_data): #如果输入序列符合条件,课程数据库中取到相应课程对象 subject=subject_data[inp] #学生类对象中取到课程列表,如果已有课程提示,如果无相同课程,添加入课程列表,并写入数据 student_subject_list=student_data[student_name_list.index(USER)].subject_classes if subject.classes in student_subject_list: print('您的课表中已有%s学科!'%subject.classes) else: student_subject_list.append(subject.classes) student_data_flush(student_data) print('课程关联成功') else:print('选择有误,请重新输入') else:print('选择有误,请重新输入') def has_subject(): """ 显示已选课程函数 :return: """ #读取学生类数据库和学生姓名列表,两个列表的下标相匹配 student_data=student_data_read() student_name_list=student_name() #读取学生对象中的对应课程列表信息,打印所有课程信息 student_subject_list=student_data[student_name_list.index(USER)].subject_classes row=prettytable.PrettyTable() row.field_names=['序列号','课程名'] for item in student_subject_list: row.add_row([student_subject_list.index(item),item]) print(row) return student_subject_list def s_logout(): sys.exit('程序退出!') def show_menu(): """ 登录后的菜单信息函数 :return: """ row=prettytable.PrettyTable() row.field_names=['选择课程','查看已选课程','上课','教学事故','退出程序'] row.add_row([0,1,2,3,'3&q&quit']) print(row) def attend(): """ 上课函数 :return: """ #读取学生类数据库和学生姓名列表,两个列表的下标相匹配 student_data=student_data_read() student_name_list=student_name() student_subject_list=student_data[student_name_list.index(USER)].subject_classes for index,item in enumerate(student_subject_list): print(index,item) inp=input('请选择课程对应的序列号:') #选择上课的目标课程 if inp.isdigit(): inp=int(inp) if inp < len(student_subject_list): #如果符合序列号标准 #确认课程名称 subject_classes=student_subject_list[inp] #读取课程对象数据 subject_data=manage_sys.subject_data_read() #确认相应的课程对象 for item in subject_data: if item.classes==subject_classes: subject_obj=item #调用课程对象的上课方法 subject_obj.attend_class() else:print('选择有误') else:print('选择有误!') def s_accidents(): """ 教学事故函数,与上课函数相同 :return: """ student_data=student_data_read() student_name_list=student_name() student_subject_list=student_data[student_name_list.index(USER)].subject_classes for index,item in enumerate(student_subject_list): print(index,item) inp=input('请选择课程对应的序列号:') if inp.isdigit(): inp=int(inp) if inp < len(student_subject_list): subject_classes=student_subject_list[inp] subject_data=manage_sys.subject_data_read() for item in subject_data: if item.classes==subject_classes: subject_obj=item #调用课程对象的教学事故方法 subject_obj.accidents() else:print('选择有误') else:print('选择有误!') def main2(): """ 登录后的菜单选择界面 :return: """ #将函数名形成列表,选择后执行函数 menu=[choice_subject,has_subject,attend,s_accidents,s_logout] while True: show_menu() inp=input('请选择操作对应的序列号:') if inp == 'q' or inp == 'quit': s_logout() elif inp.isdigit(): inp=int(inp) if inp < len(menu): menu[inp]() else:print('输入有误,请重新输入') else:print('输入有误,请重新输入~') def main(): """ 主函数入口 :return: """ print('''1.登录 2.注册''') inp=input('请选择相应操作序列号:') if inp == '1': res=s_login() if res: main2() elif inp=='2': regist() else:print('选择有误!系统退出') # if __name__ == '__main__': # main()
data目录都是数据库文件,直接手动创建即可.收工!