• 学生选课系统


    题目要求

    利用规范化目录结构完成一个学生选课系统。
    角色:学生、管理员。
    功能分析:
    用户登录之后就可以直接判断用户身份,是学生还是管理员。
    学生登录之后有以下几个功能:
    查看所有课程。
    选择课程。
    查看所选课程。
    退出程序。
    管理员登录之后有以下几个功能:
    创建课程(需要记录日志)。
    创建学生账号(需要记录日志)。
    查看所有课程。
    查看所有学生。
    查看所有学生的选课情况。
    退出程序。
    课程属性:课程名,价格,周期,老师。
    学生属性:姓名,所选课程。
    管理员属性:姓名。

    start

    import os
    import sys
    BATH_DIR = os.path.dirname(os.path.dirname(file))
    sys.path.append(BATH_DIR)

    添加搜索路径 确定当前工程的搜索路径 定位到 老师版本学生选课系统,可千万不能变成每周大作业了 为了查找具体的路径

    from core import src
    from core.src import Course
    from core.src import Student
    if name == 'main':
    src.main()

    src

    import sys
    import os
    import pickle
    from lib import common
    from conf import settings

    class Base: #

    def show_courses(self):
        with open(settings.COURSE_PATH, mode='rb') as f:
            num = 0
            while 1:
                try:
                    num += 1
                    obj = pickle.load(f)   #  # obj获取每行的课程 每行课程是一个对象
                    print(f'{num}: {obj.name} {obj.price} {obj.period}')# 打印对应的课程以及序列号
                    '''
                        1: Python周末班 12000 6个月
                        2: python脱产班 23000 6个月
                        3: 大数据 13000 4个月
                        4: java 12000 5个月
                        5: 测试 12000 6个月
                        6: 算法工程师 36000 6个月
                        7: 前端 12000 4个月
                        8: 平面设计 2345 六个月
                    '''
                except EOFError:  # 读完之后直接停止,防止循环读内容报错
                    break
    
    def exit(self):  # 使用这个函数退出,并且打印退出提示信息
        sys.exit(f'33[0;32m感谢{self.name}使用选课系统!33[0m')
        # sys.exit所用是退出并且打印内容,是sys模块里面的一个功能
    

    class Student(Base):
    operate_lst = [('查看可选课程', 'show_courses'),
    ('选择课程', 'select_course'),
    ('查看所选课程', 'show_selected_course'),
    ('退出', 'exit')] # 静态属性

    def __init__(self, name):
        self.name = name       #  定义两个属性
        self.courses = []      #  空列表,为了后面添加课程
    
    def select_course(self):
        """选择课程"""
        self.show_courses()# 先把课程打印出来 调用父类方法
        try:
            choice_num = input('33[0;32m请输入要选择的课程序号:33[0m').strip()
            # 输入要添加的课程序号
            with open(settings.COURSE_PATH, mode='rb') as f:
                for i in range(int(choice_num)):
                    # 根据输入的序号确定循环次数最终锁定选择的课程对象
                    #  比如 range(5)  循环 5 次
                    obj = pickle.load(f)  ##  拿出最后一个  最后被覆盖  # load读出来 用obj接收所选的课程对象
                self.courses.append(obj)   #  将课程添加到里面
            print(f'33[0;32m您已经成功添加了{obj.name}课程33[0m')
            # 把所选的课程添加到学生对象所对应的课程列表中
        
        except Exception:
            print('输入有误....')
    
    def show_selected_course(self):
        """查看所选课程"""
        print(f'33[0;32m您已报名如下课程33[0m')
        for obj_course in self.courses:
            # 循环此学生对象的列表,然后把所有课程的打印,每个课程也是一个对象
            print(f'33[0;32m课程名:{obj_course.name},课程价格:{obj_course.price} 课程周期:{obj_course.period}33[0m')
    
    def exit(self):
        """退出之前要将学生选择的课程添加上"""
        with open(settings.STUDENT_PATH, mode='rb') as f1, 
                open(f'{settings.STUDENT_PATH}_bak', mode='wb') as f2:
            '''打开两个文件,读旧文件,写新文件'''
            while 1:   # 循环读内容
                try:
                    obj = pickle.load(f1)
                    pickle.dump(self if obj.name == self.name else obj, f2)
                    ''' 把相应的对象名修改成现在的,其他的对象名直接写入
                    
                    '''
                except EOFError:
                    break
        os.remove(settings.STUDENT_PATH)
        os.rename(f'{settings.STUDENT_PATH}_bak', settings.STUDENT_PATH)   #  改名字
        super().exit()
    
    @classmethod
    def get_obj(cls, username):
        """此方法是区别学生与管理员登录,学生登录就会去文件中取对象,管理员登录则直接userinfo获取管理员用户名密码"""
        with open(settings.STUDENT_PATH, mode='rb') as f1:
            while 1:
                try:
                    obj = pickle.load(f1)
                    print(obj)
                    if username == obj.name:
                        return obj
                except EOFError:
                    break
    

    class Manager(Base):
    operate_lst = [('创建课程', 'create_course'),
    ('创建学生', 'create_student'),
    ('查看可选课程', 'show_courses'),
    ('查看所有学生', 'show_students'),
    ('查看所有学生选课情况', 'show_students_courses'),
    ('退出', 'exit')]

    def __init__(self, name):
        self.name = name
    
    def create_course(self):
        """创建课程"""
        course = getattr(sys.modules[__name__], 'Course')
        name, price, period = input('请依次输入课程名,价格以及课程周期,以|分割').strip().split('|')
        obj = course(name, price, period)
        with open(settings.COURSE_PATH, mode='ab') as f1:
            pickle.dump(obj, f1)
        logger = common.record_logger()
        logger.info(f'成功创建{name}课程')
    
    def create_student(self):
        """创建学生"""
        student_username = input('33[0;32m 请输入学生姓名:33[0m').strip()
        student_password = input('33[0;32m 请输入学生密码:33[0m').strip()
        student_pwd_md5 = common.hashlib_md5(student_password)
        with open(settings.USERINFO_PATH, encoding='utf-8', mode='a') as f1:
            f1.write(f'
    {student_username}|{student_pwd_md5}|Student')
        with open(settings.STUDENT_PATH, mode='ab') as f:
            obj = getattr(sys.modules[__name__], 'Student')(student_username)
            pickle.dump(obj, f)
        logger = common.record_logger()
        logger.info(f'成功您已成功创建学生账号:{student_username},初始密码:{student_password}')
    
    def show_students(self):
        """查看所有学生"""
        with open(settings.STUDENT_PATH, mode='rb') as f1:
            while 1:
                try:
                    obj = pickle.load(f1)
                    print(obj.name)
                except EOFError:
                    break
    
    def show_students_courses(self):
        """查看所有学生选课情况"""
        with open(settings.STUDENT_PATH, mode='rb') as f1:
            while 1:
                try:
                    obj = pickle.load(f1)
                    print(f'33[0;32m学生:{obj.name},所选课程:
                    {["%s-%s-%s" %(course.name,course.price,course.period) for course in obj.courses]}33[0m')
                except EOFError:
                    break
    
    def exit(self):
        """退出"""
        super().exit()
    
    @classmethod
    def get_obj(cls, username):
        return Manager(username)  #  实例化的过程
    

    class Course:
    def init(self, name, price, period):
    self.name = name
    self.price = price
    self.period = period
    self.teacher = None

    def login():
    """登陆逻辑,此处是用了单次登陆验证,你也可以根据自己的需求改成三次登陆失败才返回False"""
    count = 1
    while count < 4:
    username = input('请输入用户名:').strip()
    password = input('请输入密码:').strip()
    pwd_md5 = common.hashlib_md5(password) # 这一步是加密
    with open(settings.USERINFO_PATH,mode='r', encoding='utf-8') as f1:
    for line in f1: # 一行一行读取
    if not line.strip(): # 如果是空字符串,不空就是 True 继续执行
    continue # 继续走 for
    user, pwd, identify = line.strip().split('|') #去掉结尾 分割之后是列表
    if user == username and pwd == pwd_md5:
    return {'username': user, 'identify': identify, 'auth': True} # 成功了 这个状态就是True
    else:
    print('用户名或者密码错误,请重新输入')
    count += 1
    return {'username': username, 'identify': None, 'auth': False} # 失败了就把状态改为 False

    def main():
    print('33[0;32m欢迎访问选课系统,请先登录33[0m')
    dict_auth = login()
    print(f"33[0;32m登陆成功,欢迎{dict_auth['username']},您的身份是{dict_auth['identify']}33[0m")
    if dict_auth['auth']:
    '''根据不同的身份,进行相应的操作,登录成功状态就改为 True'''
    if hasattr(sys.modules[name], dict_auth['identify']): # 必须找到这个类,才能调用后续的方法
    '''反射到本模块,找到 identify 对应的类 反射 判断对象是否存在,存在就是返回 True 否则 False'''
    cls = getattr(sys.modules[name], dict_auth['identify']) # 得到类名地址
    '''
    如果是管理者登录:
    obj = cls(dict_auth['username'])
    如果是学生登录:
    从Student文件中 读取该学生对象并返回:
    打开文件,读取文件: pickle.load(f) dic_auth['username'] == obj.name
    obj = 文件中读取的学生对象
    '''
    obj = cls.get_obj(dict_auth['username']) # 管理员与学生都定义了此方法,鸭子类型.
    while 1:
    for num, option in enumerate(cls.operate_lst, 0): # 类名. 这个万能的点 # num 将元组解构
    '''
    operate_lst = [('创建课程', 'create_course'),
    ('创建学生', 'create_student'),
    ('查看可选课程', 'show_courses'),
    ('查看所有学生', 'show_students'),
    ('查看所有学生选课情况', 'show_students_courses'),
    ('退出', 'exit')]
    '''
    print(f'{num+1}: {option[0]}')
    '''
    输出是这个东东
    1: 创建课程
    2: 创建学生
    3: 查看可选课程
    4: 查看所有学生
    5: 查看所有学生选课情况
    6: 退出

                    num 的作用就是解构,坤坤说这些都是旧的知识点,我的妈呀,难受,竟然都不知道
                '''
            choice_num = int(input('33[0;32m 请输入选项:33[0m').strip())
            getattr(obj, cls.operate_lst[choice_num - 1][1])()  # getattr(obj,'create_course')() 已经调用这个函数了
    
    else:
        print('三次验证失败,系统自动退出')
        return False
    
    settings

    import os
    import logging.config
    BATH_DIR = os.path.dirname(os.path.dirname(file))
    USERINFO_PATH = os.path.join(BATH_DIR, 'db', 'user_info')
    COURSE_PATH = os.path.join(BATH_DIR, 'db', 'Course')
    STUDENT_PATH = os.path.join(BATH_DIR, 'db', 'Student')
    LOGGING_PATH = os.path.join(BATH_DIR, 'log', 'admin.log')
    SIMPLE_FORMAT = '[%(asctime)s] %(message)s'

    LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,

    'formatters': {
        
        'simple': {
            'format': SIMPLE_FORMAT,
        },
    },
    'filters': {},
    'handlers': {
        # 打印到终端的日志
        'stream': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到屏幕
            'formatter': 'simple'
        },
        # 打印到文件的日志,收集info及以上的日志
        'file': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
            'formatter': 'simple',
            'filename': LOGGING_PATH,  # 日志文件
            'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
            'backupCount': 5,
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },
    },
    'loggers': {
        # logging.getLogger(__name__)拿到的logger配置
        '': {
            'handlers': ['stream', 'file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
    

    }

    common

    import hashlib
    import logging.config
    from conf.settings import LOGGING_DIC

    def hashlib_md5(password):
    """密码加密"""
    ret = hashlib.md5()
    ret.update(password.encode('utf-8'))
    return ret.hexdigest()

    def record_logger():
    """记录日志"""
    logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置
    logger = logging.getLogger() # 生成一个log实例
    return logger

  • 相关阅读:
    帧锁定同步算法
    为 Raft 引入 leader lease 机制解决集群脑裂时的 stale read 问题
    etcd:从应用场景到实现原理的全方位解读
    给定一个二叉搜索树(BST),找到树中第 K 小的节点
    UDP如何实现可靠传输
    理解TCP/IP三次握手与四次挥手的正确姿势
    Redis持久化
    Redis提供的持久化机制(RDB和AOF)
    redis渐进式 rehash
    redis rehash
  • 原文地址:https://www.cnblogs.com/hualibokeyuan/p/11372414.html
Copyright © 2020-2023  润新知