首页 > 其他分享 >选课系统编写思路

选课系统编写思路

时间:2022-11-13 21:01:13浏览次数:33  
标签:.__ name 选课 self pwd mode 编写 思路 def

选课系统编写思路

搭建框架

  • 依旧是使用三层架构的框架来编写程序
  • 编写的时候同样使用软件开发目录规范
  • 不同的是尝试将面向对象的三大核心——封装、继承、多态尽量应用进去

编写思路

  1. 创建开发目录及可能要用到的文件

  2. 架构设计

    image

  3. 编写start、src、三个视窗,用空函数体搭建起用户交互层,枚举出功能

    点击查看代码
    from core import admin, teacher, student
    
    modules_dict = {
        '1': admin,
        '2': teacher,
        '3': student
    }
    
    def run():
        while True:
            choice = input("""
    ===========中国'慕棵'选课系统==========
        1 管理员通道
        2 老师通道
        3 学生通道
    ===============<首页>================
    请输入视图编号(q退出程序):""")
            if choice == 'q':
                print('bye~~')
                return
            if choice in modules_dict:
                modules_dict.get(choice).run()
            else:
                print('请输入正确的编号')
    
  4. 编写管理员的注册功能,串写一遍架构,能帮助我们理清思路,调什么接口,接口调什么类

  5. 注册时发现类体中,独有的数据属性是实现各功能关键,根据每类对象的功能,列出选课系统中所有类可能用到的数据属性,并编写对应类的双下init功能。

    如下,这里的程序中顺带将处理数据的dbhandler写了,相较原本只能读写一种数据的select和save,这次我们采取了子类继承父类的select和save方法,让它们根据类和对象自行判断存储的路径,让不同的数据对象存到了不同的文件夹下以便管理。

    还有,日志功能也写到了这里,每个类中都产生了一个记录者,这样当在有对象进行一些功能的操作时,就会访问到类中的记录者,对程序进行记录。

    对于封装和伪装也少量的应用了一下,逻辑是:name属性作为唯一凭证,只能查看,不能修改;

    密码不能查看,只能校验和修改,所以单独开放了两个功能。

    点击查看代码
    ```py
    
    import logging
    import os
    import pickle
    
    from lib import common
    from conf import settings
    
    
    class DBHandler:
        __name = '子类中应该有__name作为唯一凭证'
        __pwd = '对于有密码的子类可以校验密码和更改密码'
    
        def save(self):
     	   path_dir = os.path.join(settings.DB_DIR, self.__class__.__name__)
     	   if not os.path.isdir(path_dir):
     		   os.mkdir(path_dir)
     	   obj_path = os.path.join(path_dir, self.name)
     	   with open(obj_path, 'wb') as f:
     		   pickle.dump(self, f)
    
        @classmethod
        def select(cls, name):
     	   path_dir = os.path.join(settings.DB_DIR, cls.__name__)
     	   if not os.path.isdir(path_dir):
     		   os.mkdir(path_dir)
     	   obj_path = os.path.join(path_dir, name)
     	   if os.path.isfile(obj_path):
     		   with open(obj_path, 'rb') as f:
     			   return pickle.load(f)
    
        @classmethod
        def select_all_obj_name(cls):  # 拿到类下的所有对象
     	   path_dir = os.path.join(settings.DB_DIR, cls.__name__)
     	   if not os.path.isdir(path_dir):
     		   os.mkdir(path_dir)
     	   return os.listdir(path_dir)  # 可能返回一个名称列表或者空列表
    
    
    class Admin(DBHandler):
        logger = logging.getLogger('管理员记录')
    
        def __init__(self, name, pwd):
     	   self.__name = name
     	   self.__pwd = pwd
     	   self.save()
    
        @property
        def name(self):
     	   return self.__name
    
        def verify_pwd(self, pwd):
     	   return self.__pwd == pwd
    
        def alter_pwd(self, new_pwd):
     	   self.__pwd = new_pwd
    
    
    
    class School(DBHandler):
        logger = logging.getLogger('学校记录')
    
        def __init__(self, name, addr):
     	   self.__name = name
     	   self.addr = addr
     	   self.course_list = []
     	   self.valid = True
     	   self.save()
    
        @property
        def name(self):
     	   return self.__name
    
    
    class Teacher(DBHandler):
        logger = logging.getLogger('老师记录')
    
        def __init__(self, name, pwd):
     	   self.__name = name
     	   self.__pwd = pwd
     	   self.valid = True
     	   self.course_list = []
     	   self.save()
    
        @property
        def name(self):
     	   return self.__name
    
        def verify_pwd(self, pwd):
     	   return self.__pwd == pwd
    
        def alter_pwd(self, new_pwd):
     	   self.__pwd = new_pwd
    
    
    
    class Course(DBHandler):
        logger = logging.getLogger('课程记录')
    
        def __init__(self, name, period, price, tea_name, sch_name):
     	   self.__name = name
     	   self.valid = True
     	   self.__period = period
     	   self.__price = price
     	   self.__major_tea = tea_name
     	   self.school = sch_name
     	   self.tea_list = []
     	   self.stu_list = []
     	   self.email = {}  # {stu:msg}
     	   self.save()
    
        @property
        def name(self):
     	   return self.__name
    
        @property
        def showed_infos(self):
     	   return [self.name, self.__period, self.__major_tea, self.__price, self.school]
    
        @property
        def all_stu_scores(self):
     	   return [Student.select(stu).scores_list[self.name] for stu in self.stu_list]
    
    
    class Student(DBHandler):
        logger = logging.getLogger('学生记录')
    
        def __init__(self, name, pwd, age):
     	   self.__name = name
     	   self.__pwd = pwd
     	   self.age = age
     	   self.valid = True
     	   self.school = ''
     	   self.course_list = []
     	   self.scores_list = {}
     	   self.account = 0
     	   self.email = {}  # {course:msg(哪个老师的处理结果)}
     	   self.save()
    
        @property
        def name(self):
     	   return self.__name
    
        def verify_pwd(self, pwd):
     	   return self.__pwd == pwd
    
        def alter_pwd(self, new_pwd):
     	   self.__pwd = new_pwd
    
    
    </details>
    
    
    
  6. 编写每个接口的注册登录功能,因为其类似性,也可以将其整合起来,用传入参数的方式来更改一些字符,使一段代码可以满足所有的注册登录。

    而如何通过字符来调用不同的接口,显示不同的字符结果,我用到的是发射和配置字典

    点击查看代码
    # settings里写的配置字典
    MODE_DICT = {
        'Admin': {'named': '管理员', },
        'Teacher': {'named': '教师', },
        'Student': {'named': '学生', },
        'Course': {'named': '课程'}
    }
    
    # 专门写了一个py文件用于存入用户的登录态,和组织用户注册登录的功能
    from interface import user_inf
    from conf import settings
    from lib import common
    
    login_state = {
        'Admin': '',
        'Teacher': '',
        'Student': '',
    }
    
    
    def register(mode):
        view_str = settings.MODE_DICT[mode].get('named')
        while True:
            print(f'--【{view_str}】注册界面--')
            username = input('请输入用户名:').strip()
            if user_inf.is_user_exist(username, mode=mode):
                print('用户已经被注册过了')
                continue
            password = input('请输入密码:').strip()
            confirm_pwd = input('请确认密码:').strip()
            if not password == confirm_pwd:
                print('两次密码不一致')
                continue
            password = common.get_hash(password)
            if mode == 'Admin':
                user_inf.register_inf(username, password, mode=mode)
                break
            if mode == 'Student':
                while True:  # 学生还有些额外的要输入的东西,让用户可以循环输入
                    age = input('请输入你的年龄:').strip()
                    if not age.isdigit():
                        print('请输入数字')
                        continue
                    break
                user_inf.register_inf(username, password, mode=mode, age=age)
                break
        print(f'{view_str}【{username}】注册成功')
        print('~返回登录注册界面~')
    
    
    def login(mode):
        view_str = settings.MODE_DICT[mode].get('named')
        while True:
            print(f'--{view_str}登录功能--')
            username = input('请输入用户名(q返回上一页):').strip()
            if username == 'q':
                return False
            if not user_inf.is_user_exist(username, mode=mode):
                print('用户不存在')
                continue
            password = input('请输入密码:').strip()
            password = common.get_hash(password)
            flag = user_inf.login_inf(username, password, mode=mode)
            if flag == -1:
                print(f'用户{username}已失效,请联系管理员')
                return False
            if flag:
                print(f'{view_str}【{username}】登录成功!')
                login_state[mode] = username
                return True
            print('密码不对!')
    
    
    def logout(mode):
        view_str = settings.MODE_DICT[mode].get('named')
        name = login_state[mode]
        login_state[mode] = ''
        return f'{view_str}【{name}】已登出'
    
    
    def login_auth(mode):
        def outer(func):
            def inner(*args, **kwargs):
                if login_state[mode]:
                    res = func(*args, **kwargs)
                    return res
                print('您还没有登录,为您跳转到登录界面')
                login(mode)
    
            return inner
    
        return outer
    
    
    # 用于接受注册登录的接口文件user_inf.py
    from db import models
    
    
    def is_user_exist(username, mode):
        cls = getattr(models, mode)
        if cls.select(username):
            return True
        return False
    
    
    def register_inf(username, pwd, *, mode, **kwargs):
        cls = getattr(models, mode)
        cls(username, pwd, **kwargs)
    
    
    def login_inf(username, pwd, *, mode):
        cls = getattr(models, mode)
        user_obj = cls.select(username)
        if hasattr(user_obj, 'valid'):  # 如果有这个属性
            if not user_obj.valid:  # 失效情况下,返回-1
                return -1
        return user_obj.verify_pwd(pwd)
    
  7. 完成注册登录功能的独立后,尝试将注册登录与各视图的核心功能给分开,如图:

    实际上就是采取了两个循环并列,当登录循环从登录成功结束时,进入核心功能循环。

    image

  8. 实现管理员创建功能,每个创建功能都大同小异,要求用户输入,判断是否存在同名对象,如果无同名则去调创建的接口,录入一些信息,并在管理员的类中加入一个创建xx的功能,做对应的日志记录,调用相应的类,并保存到pickle文件中。

    def create_school():
        while True:
            sch_name = input('请输入注册的学校名(q返回上一页):').strip()
            if sch_name == 'q':
                return
            if user_inf.is_user_exist(sch_name, 'School'):
                print('该学校已经注册过了')
                continue
            addr = input('输入学校地址:').strip()
            admin_inf.create_school_inf(sch_name, addr, user_login.login_state[MODE])
            print(f'学校{sch_name}创建成功!')
    
  9. 实现学生选学校功能,选课程功能

    先判断学生是否绑定过学校,没有就要求绑定学校,有才能选课。

    都是先打印有效的学校或者绑定学校下的有效课程,调学生接口用类方法取所有的学校对象,和用对象方法取学校下的课程,拿到相应的信息,这里打印表格调用了common中的功能,使用第三方模块,快速的将二维列表打印成表格的样式。

    再要求用户输入相应的编号,如果编号输入有问题就重新输,直到按q退出,有效编号就转化为列表中的对应对象名称,我们再将学校课程的名字传入接口层处理,都调用学生的对象方法使学生和学校、课程互相绑定。

    def choose_school():
        # 先判断学生有没有绑定过学校
        sch_name = student_inf.is_bind_school(user_login.login_state[MODE])
        if sch_name:
            ask = input('你已经绑定过学校了,是否解绑(y/n)').strip()
            if ask != 'y':
                print(f'保持学校{sch_name}的绑定,正在返回学生菜单')
                return
            print('已解绑原学校,可以重新绑定其他学校')
        while True:
            # 打印名单
            name_list = public_inf.get_valid_name('School')
            print(common.get_index_table([f'学校名'], name_list))
            choice = input(f'输入学校编号以绑定(q返回学生菜单):').strip()
            if choice == 'q':
                return
            if not choice.isdigit():
                print('请输入数字')
                continue
            choice = int(choice) - 1
            if choice not in range(len(name_list)):
                print('请输入有效编号')
                continue
            sch_name = name_list[choice]
            # 绑定学校
            student_inf.bind_school_inf(sch_name, user_login.login_state[MODE])
            print(f'绑定学校{sch_name}成功')
            break
    
  10. 实现学生查分功能,预留有分数独有数据,我们只要在类方法中将这个数据返回出去,接口层处理为易于展示的二维列表,交互层在调用打印表格的公共方法即可打印学生的分数

  11. 实现老师选课、查课

    选课是将所有的课程对象拿过来选,查课是通过自己对象中的course_list的数据属性来查看

  12. 实现老师查分、改分

    老师查看自己的课表,选一门课来查看,这样就能看到课下所有学生这门课的分数。

    改分就是在查分的基础上,选择一个学生来修改分数。

    这里涉及的数据操作无外乎对老师的对象的课程进行遍历,对课程对象的学生进行遍历,对学生对象的分数属性进行修改。

标签:.__,name,选课,self,pwd,mode,编写,思路,def
From: https://www.cnblogs.com/Leethon-lizhilog/p/16886941.html

相关文章

  • jvm调优思路及调优案例
    jvm调优思路及调优案例​ 我们说jvm调优,其实就是不断测试调整jvm的运行参数,尽可能让对象都在新生代(Eden)里分配和回收,尽量别让太多对象频繁进入老年代,避免频繁对老年代......
  • 编写程序练习直接、间接、相对、基址变址寻址
    直接寻址方式操作数在存储单元中,指令的操作码之后给出该存储单元的有效地址EA。指令中,EA可以是数值形式,也可以是符号地址形式;例如:MOVAX,[100H];  数值地址必须加方......
  • 选课系统
    选课系统1.项目功能2.项目准备3.管理员功能4.学生功能5.讲师功能1.项目功能管理员功能注册、登录、创建学校、创建课程、创建老师讲师功能登录、查看课程、选......
  • makefile编写
    /****************************************************/1.目录结构在文件夹下执行“tree”命令,没有该命令则安装:sudoaptinstalltree.├──app......
  • 选课系统编写思路
    选课系统编写思路一、搭建框架依旧是使用三层架构的框架来编写程序编写的时候同样使用软件开发目录规范二、编写思路1、创建目录及各个文件2、之后打开settings,设......
  • 系统宕机,内存溢出等典型问题排查思路及工具使用
     问题范围:平台典型后端问题,如宕机、服务响应慢、节点丢失、CPU高、内存高、数据库响应慢等。分析这类问题虽然没有固定套路,但是有大概方向。工具范围:平台自带服务质......
  • 补充一下学生选课系统的表间关系的建立
    学生选课系统--表间关系的分析以及实现那先来看一眼我一共建立了哪些表吧!1、课程信息表2、学生个人信息表3、教师个人信息表4、课程信息和学生信息多对多关系建立起来......
  • 煎熬周末之选课系统!!!!!!!!!!!!!!!!
    项目开端选课系统锻炼对三层结构掌握情况并拓展练习对各个模块运用情况,对比ATM项目虽然多了几个模块,但是并没有多出来很难理解的知识!最初听完比较懵,仔细梳理了之后,逻辑并......
  • 选课系统思路
    管理员视图注册功能:register()1.获取用户输入:用户名和密码2.接入管理员视图接口判断是否已经注册models:select_obj方法,db_handler中select函数3.保存信息:在mode......
  • Qt编写4K/8K大分辨率播放器(8K占用1%CPU)
    一、前言在经过多种内核的洗礼以后,逐渐对不同内核的不同音视频文件和视频流进行大量的对比测试,比如测试对各种格式的支持性,对各种网络流的支持程度,在同一个地址下占用的CP......