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目录都是数据库文件,直接手动创建即可.收工!

 

posted @ 2016-06-24 11:04  ccorz  阅读(696)  评论(0编辑  收藏  举报