zoukankan      html  css  js  c++  java
  • 学生选课系统

    题目要求

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

    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

  • 相关阅读:
    how to uninstall devkit
    asp.net中bin目录下的 dll.refresh文件
    查找2个分支的共同父节点
    Three ways to do WCF instance management
    WCF Concurrency (Single, Multiple, and Reentrant) and Throttling
    检查string是否为double
    How to hide TabPage from TabControl
    获取当前系统中的时区
    git svn cygwin_exception
    lodoop打印控制具体解释
  • 原文地址:https://www.cnblogs.com/hualibokeyuan/p/11372414.html
Copyright © 2011-2022 走看看