这周的作业有点糙,迁就看吧,给大家点思路:
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目录都是数据库文件,直接手动创建即可.收工!