选课系统项目
前言
需求
选课系统
角色:学校、学员、课程、讲师
要求:
1. 创建北京、上海 2 所学校
2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开
3. 课程包含,周期,价格,通过学校创建课程
4. 通过学校创建班级, 班级关联课程、讲师5. 创建学员时,选择学校,关联班级
5. 创建讲师角色时要关联学校,
6. 提供三个角色接口
6.1 学员视图, 可以注册, 交学费, 选择班级,
6.2 讲师视图, 讲师可管理自己的班级, 上课时选择班级, 查看班级学员列表 , 修改所管理的学员的成绩
6.3 管理视图,创建讲师, 创建班级,创建课程
7. 上面的操作产生的数据都通过pickle序列化保存到文件里
功能提炼
1.管理员功能
注册功能
登录功能
创建学校
创建课程
创建老师
2.讲师功能
登录功能
选择课程
查看课程
查看学生分数
修改学生分数
3.学生功能
注册功能
登录功能
选择学校
选择课程
查看课程分数
架构设计
- 第一层做分层展示。src展示层展示管理员视图、讲师视图、学员视图。每个视图下展示自己的功能。
- 第三层创建models.py存储所有的类,只有该models.py文件内的代码有资格调用db_handler。使用pickle模块将对象存储在文件,接口层只访问Model文件的各种类,只跟类打交道。使用类中的方法去进行数据存取。
初期搭建
src模块字典
管理员视图、讲师视图、学生视图都有run函数。如admin_view.py的run函数调用管理员的功能字典。
视图层功能字典
管理员注册功能
展示层
没什么好说的,调用接口,和以前一样
接口层
首先要说明的是:
接口层只能访问db目录下的models文件,model文件有Admin这个管理员类,每次注册都会产生一个不同的管理员对象。用pickle模块以文件的形式将管理员对象存在db/admim这个目录下(文件名就是管理员名)。
接口层实现了什么功能:
- 判断用户是否存在:注意这里调用的是Admin类中的方法,类调用类中方法,是不会进行自动操作的!也就是说第一个参数要手动传。
- 给密码加密:get_hash应该写在common.py文件内,使用时导入。
- 用户不存在时,创建管理员对象并保存:调用Admin类,在类中的__init__方法设置调用save_obj方法,使得产生的对象自动保存。
Admin类
__class__ 和 __name__获取类的字符串名 (重要)
# 1.手中是对象的情况
'''
obj.__class__ 获取产生对象的类名(可调用)
obj.__class__.__name__ 获取产生对象的类的字符串名
'''
# 2.手中是类的情况
'''
class.__name__ 获取当前类的字符串名
'''
save_obj
- 将当前的对象传入db_handler的save方法:
- 先根据对象所属的类 拼接出类文件夹的路径
- 类文件夹不存在则创建
- 根据对象的name属性,拼接出用户路径
- 使用pickle模块,以二进制模式打开文件,保存对象
自动保存 (重要)
接口层调用admin类产生对象:
对象调用后,先执行元类的双下call,将admin类传入双下call,再用new方法产生一新对象,后用admin类调用双下init,将新对象和属性传进init。给对象添加name,pwd等属性,然后执行对象的save_obj保存对象。最后双下call返回对象
select_obj
用于接口层用的是类调用即:admin.select_obj,所有干脆将select_obj装饰一下,自动把调用他的类admin传进去,然后在db_handler内获取一下admin类的字符串名'admin'用于拼接目录。
感觉用静态方法也可以实现相应的功能。
这里唯一不建议使用的就是select_obj(self)这种动态方法,因为我们不需要将对象自动传入,self反而占了个形参的位置,容易引起混淆。
db_handler select:
- 通过传进来的类 获取类的字符串名 用于拼接类文件夹路径
- 通过传进来的用户输入 拼接用户路径 并判断路径是否存在
- 如果路径存在则返回 用户对象
登录功能
admins视图层:
admin接口层:
通用校验装饰器
装饰器写三个,每个模块写一个,全局字典写三个,每个模块放一个。然后退出模块的时候将全局字典清空,这样也不是不行,但是有更好的方法:
写一个有参装饰器,装饰每个视图里面的功能函数。根据有参装饰器传参的不同,去调用不同模块的全局字典。比如@auth_login('student')这个传的是'student',此时就去调学生视图的全局字典。
全局字典有值,则表示学习用户已经登录,可以执行当前函数。
如果全局字典没值,就去调用学生模块的登录方法。
原来要写三个装饰器,现在用写一个了!
核心:对于视图层的功能函数,使用当前视图的全局字典进行登录校验。
比如,student_view下的choice_lessions选课功能进行登录校验时,实际上还是要用学生视图的全局字典。
装饰器健壮性:
全局字典的名字
使用这个有参装饰器必须保证:
- 每个视图文件内都有一个全局字典
- 全局字典的名字相同
循环导入
管理员创建学校
展示层
这里给接口传入了三个参数:
- 学校的名字
- 学校的地址
- 当前管理员的名字
接口层
接口层主要干两件事:
- 判断管理员输入的学校名字,是否已经创建
- 若没有创建过,则创建学校对象并保存到文件夹
完成这两件事需要写School类。
School类
给学校定义了三个属性:
- 学校名
- 学校地址
- 该学校包含哪些课程
school类写好后,可以将管理员类添加一个方法create_school,此方法实际就是产生一个学校对象,并保存。
然后我们就可以用管理员对象去调用这个方法,来实现创建学校对象的操作,看上去更合理(脱裤子放屁)。
代码优化(重要)
Admin类和Student类中,代码有很多重复的地方,比如这两个类都有查找和保存的方法。
对类中相同的功能进行抽象,再继承:
基本绑定关系
学生选课
使用临时列表,来存储学生选择的课程时。
1.注意给临时列表去重
2.临时列表中选择的课程可能与学生对象里面已经选择过的课程有重复的地方
3.求交集,算出真正新增的课程
4.给学生新增成绩
5.给真正新增的课程的课程对象添加学生