学生选课系统练手小项目

学生选课系统练手小项目

文件目录:
学生选课系统(一级目录)
​		——bin(二级目录)
​			——start.py
​		——conf(二级目录)
​			——settings.py
​		——core(二级目录)
​			——src.py
​		——db(二级目录)
​			——Course.txt
			——Student.txt
			——user_info.txt
​		——lib(二级目录)
​			——common.py
​		——log(二级目录)
​			——Admin.log
​		——README(二级目录)

README

需求:
利用规范化目录结构完成一个学生选课系统。
    角色:学生、管理员。
    功能分析:
        用户登录之后就可以直接判断用户身份,是学生还是管理员。
        学生登录之后有以下几个功能:
            查看所有课程。
            选择课程。
            查看所选课程。
            退出程序。
        管理员登录之后有以下几个功能:
            创建课程(需要记录日志)。
            创建学生账号(需要记录日志)。
            查看所有课程。
            查看所有学生。
            查看所有学生的选课情况。
            退出程序。
    课程属性:课程名,价格,周期,老师。
    学生属性:姓名,所选课程。
    管理员属性:姓名。
分析:
难点:
1,学生登录成功了,证明储存学生对象的文件Student有这个对象name,从文件中把这个对象取
出来,然后进行相应操作
2,如何取出正确的对象,我们可以根据用户名与obj.name是否相等来取出相应的对象。
3,学生原来选取了python课程,这次登录又选取了linux,在该学生退出之前,要把这个修改的对象重新写进文件


文件目录说明:
bin:这个目录一般存放的是启动文件,程序的入口就是整个文件。
conf:这个目录一般存放的是配置文件,是一些不变的常量和路径等。
core:这个是项目的核心目录,下面的文件执行主业务功能,所以功能函数都写在这里面。
db:这个就是数据库目录,就是存放我们的数据的。
lib:这个是公用目录,它下面的文件写的代码是可以被重复使用的。
log:这个看名字就知道事日志目录,里面存放的肯定也是我们的日志文件。

流程图
在这里插入图片描述
bin

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()

conf

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,
        },
    },
}

core

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)
                    print(f'{num}: {obj.name} {obj.price} {obj.period}')
                except EOFError:
                    break
    
    def exit(self):
        sys.exit(f'\033[0;32m感谢{self.name}使用选课系统!\033[0m')


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('\033[0;32m请输入要选择的课程序号:\033[0m').strip()
            with open(settings.COURSE_PATH, mode='rb') as f:
                for i in range(int(choice_num)):  # 根据输入的序号确定循环次数最终锁定选择的课程对象
                    obj = pickle.load(f)
                self.courses.append(obj)
            print(f'\033[0;32m您已经成功添加了{obj.name}课程\033[0m')
        
        except Exception:
            print('输入有误....')
    
    def show_selected_course(self):
        """查看所选课程"""
        print(f'\033[0;32m您已报名如下课程\033[0m')
        for obj_course in self.courses:
            print(f'\033[0;32m课程名:{obj_course.name},课程价格:{obj_course.price} 课程周期:{obj_course.period}\033[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)
                    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('\033[0;32m 请输入学生姓名:\033[0m').strip()
        student_password = input('\033[0;32m 请输入学生密码:\033[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'\n{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'\033[0;32m学生:{obj.name},所选课程:\
                    {["%s-%s-%s" %(course.name,course.price,course.period) for course in obj.courses]}\033[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, encoding='utf-8') as f1:
            for line in f1:
                if not line.strip(): continue
                user, pwd, identify = line.strip().split('|')
                if user == username and pwd == pwd_md5:
                    return {'username': user, 'identify': identify, 'auth': True}
            else:
                print('用户名或者密码错误,请重新输入')
        count += 1
    return {'username': username, 'identify': None, 'auth': False}


def main():
    print('\033[0;32m欢迎访问选课系统,请先登录\033[0m')
    dict_auth = login()
    print(f"\033[0;32m登陆成功,欢迎{dict_auth['username']},您的身份是{dict_auth['identify']}\033[0m")
    if dict_auth['auth']:
        '''根据不同的身份,进行相应的操作,利用反射'''
        if hasattr(sys.modules[__name__], dict_auth['identify']):
            cls = getattr(sys.modules[__name__], dict_auth['identify'])
        obj = cls.get_obj(dict_auth['username'])  # 管理员与学生都定义了此方法,鸭子类型。
        while 1:
            for num, option in enumerate(cls.operate_lst, 0):
                print(f'{num+1}: {option[0]}')
            choice_num = int(input('\033[0;32m 请输入选项:\033[0m').strip())
            getattr(obj, cls.operate_lst[choice_num - 1][1])()
    
    else:
        print('三次验证失败,系统自动退出')
        return False

db

Course.txt
Student.txt
user_info.txt

lib

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

log

Admin.log

代码下载地址:https://github.com/pl1649947109/pl_share.git

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值