相信很多人在初学Python的时候,经常最后作业就是完成一个学生管理系统,但是我们来做一个完美的学生管理系统,并且将数据储存到数据库里。
我们先看看我们的数据库怎么设置。
首先呢,我选择用的是SQL Server
然后,我们的数据库名称为学生管理系统
接着,新建一张表,我设置表的名称为学生信息表。
最后,去设置表的列名和类型,我的设置如下:
接下来,我们开始做Python代码啦。
1.我们的导入库有:
from tkinter import * from tkinter.messagebox import askokcancel, showinfo import tkinter.ttk as ttk import pyodbc import os import logging import pandas as pd from tkinter.filedialog import askopenfilename
2.链接到SQL Server:
# 连接到 SQL ServerConnect to SQL Server cn = pyodbc.connect('DRIVER={SQL Server};SERVER=(local);DATABASE=学生管理系统;UID=LYD\\lyd;Trusted_Connection=yes
注意:这里面要注意的是因为我的服务器名称是(local)如果你有其他服务器,那么只要在SERVER=(local)中,改成你的服务器名称。然后我的用户名为LYD\lyd,用户名在UID=LYD\\lyd中更改。然后我没有,如果你有就去改一下就好了
3.GUI界面的设置:
def main(): root.geometry('800x600') # 设置窗口初始大小 root.title(systitle) # 设置系统标题 # 创建系统菜单 menubar = Menu(root) # 创建Menu对象menubar,将作为root窗口中的菜单 root.config(menu=menubar) # 将menubar菜单作为root窗口的顶层菜单栏 # menuStudent将作为menubar菜单的子菜单 menuStudent = Menu(menubar, tearoff=0) menuStudent.add_command(label='添加新学生', font=('宋体', 10), command=addStudent) menuStudent.add_command(label='显示全部学生信息', font=('宋体', 10), command=showAllStudent) menuStudent.add_command(label='查找/修改/删除学生信息', font=('宋体', 10), command=checkUpdateStudent) menuStudent.add_command(label='批量导入学生信息', font=('宋体', 10), command=importStudents) # 菜单file添加为menubar的子菜单 menubar.add_cascade(label='学生管理', font=('宋体', 10), menu=menuStudent) menuHelp = Menu(menubar, tearoff=0) # help将作为menubar菜单的子菜单 menuHelp.add_command(label='查看日志', font=('宋体', 10), command=viewLog) menuHelp.add_command(label='关于我们', font=('宋体', 10), command=about) # 菜单help添加为menubar的子菜单 menubar.add_cascade(label='其他', font=('宋体', 10), menu=menuHelp) menubar.add_command(label='退出', font=('宋体', 10), command=root.quit) root.mainloop()
4.设置添加新学生信息:
def addStudent(): for widget in operateFrame.winfo_children(): # 清空窗口中原有的所有内容 widget.destroy() f1 = Frame(operateFrame) f1.pack() studentIdVar = StringVar() studentNameVar = StringVar() idCardVar = StringVar() telVar = StringVar() lStudentId = Label(f1, text='学号:') lStudentName = Label(f1, text='姓名:') lIdCard = Label(f1, text='身份证号码:') lTel = Label(f1, text='手机号:') tStudentId = Entry(f1, textvariable=studentIdVar) tStudentName = Entry(f1, textvariable=studentNameVar) tIdCard = Entry(f1, textvariable=idCardVar) tTel = Entry(f1, textvariable=telVar) lStudentId.grid(row=1, column=1) lStudentName.grid(row=2, column=1) lIdCard.grid(row=3, column=1) lTel.grid(row=4, column=1) tStudentId.grid(row=1, column=2) tStudentName.grid(row=2, column=2) tIdCard.grid(row=3, column=2) tTel.grid(row=4, column=2) f2 = Frame(operateFrame) f2.pack(pady=20) bReset = Button(f2, text='重置') bSave = Button(f2, text='保存') bReset.grid(row=1, column=1) bSave.grid(row=1, column=2) # 记录用户操作 logging.info('用户执行了添加新学生操作') def reset(): studentIdVar.set('') studentNameVar.set('') idCardVar.set('') telVar.set('') bReset.config(command=reset) def save(): try: id = studentIdVar.get() if not id.isdigit(): raise Exception('学号必须为数字!') name = studentNameVar.get() id_card = idCardVar.get() if len(id_card) != 18: raise Exception('身份证号码必须是18位!') tel = telVar.get() if len(tel) != 11: raise Exception('手机号必须是11位!') # 向数据库发送插入指令 cursor = cn.cursor() cursor.execute('INSERT INTO 学生信息表 VALUES (?, ?, ?, ?)', (id, name, id_card, tel)) cn.commit() showinfo('提示', '保存成功!') except Exception as e: showinfo('错误', str(e)) bSave.config(command=save)
5.设置显示全部学生信息:
def showAllStudent(): # 清空窗口中原有的所有内容 for widget in operateFrame.winfo_children(): widget.destroy() # 创建表格 tree = ttk.Treeview(operateFrame) tree["columns"] = ("学号", "姓名", "身份证号码", "手机号") tree.column("学号", width=100) tree.column("姓名", width=100) tree.column("身份证号码", width=150) tree.column("手机号", width=100) tree.heading("学号", text="学号") tree.heading("姓名", text="姓名") tree.heading("身份证号码", text="身份证号码") tree.heading("手机号", text="手机号") tree.pack(side=LEFT, fill=Y) # 从数据库中获取学生信息 cursor = cn.cursor() cursor.execute("SELECT * FROM 学生信息表") rows = cursor.fetchall() # 在表格中显示学生信息 for row in rows: tree.insert("", "end", values=row) # 记录用户操作 logging.info('用户执行了显示全部学生信息操作')
6.设置查找/修改/删除学生信息:
def checkUpdateStudent(): for widget in operateFrame.winfo_children(): widget.destroy() f1 = Frame(operateFrame) f1.pack() searchVar = StringVar() searchLabel = Label(f1, text='请输入学号:') searchEntry = Entry(f1, textvariable=searchVar) searchButton = Button(f1, text='搜索', command=lambda: searchStudent(searchVar.get())) searchLabel.grid(row=1, column=1) searchEntry.grid(row=1, column=2) searchButton.grid(row=1, column=3) def searchStudent(studentId): # 在数据库中搜索学生信息 cursor = cn.cursor() cursor.execute("SELECT * FROM 学生信息表 WHERE 学号=?", (studentId,)) row = cursor.fetchone() # 记录用户操作 logging.info('用户执行了查找/修改/删除学生信息操作') if row: showStudentInfo(row) else: showinfo('提示', '未找到该学生信息!') def showStudentInfo(studentInfo): # 清空窗口中原有的所有内容 for i in operateFrame.winfo_children(): i.destroy() f2 = Frame(operateFrame) f2.pack() studentIdVar = StringVar(value=studentInfo[0]) studentNameVar = StringVar(value=studentInfo[1]) idCardVar = StringVar(value=studentInfo[2]) telVar = StringVar(value=studentInfo[3]) lStudentId = Label(f2, text='学号:') lStudentName = Label(f2, text='姓名:') lIdCard = Label(f2, text='身份证号码:') lTel = Label(f2, text='手机号:') tStudentId = Entry(f2, textvariable=studentIdVar, state='readonly') tStudentName = Entry(f2, textvariable=studentNameVar) tIdCard = Entry(f2, textvariable=idCardVar) tTel = Entry(f2, textvariable=telVar) lStudentId.grid(row=1, column=1) lStudentName.grid(row=2, column=1) lIdCard.grid(row=3, column=1) lTel.grid(row=4, column=1) tStudentId.grid(row=1, column=2) tStudentName.grid(row=2, column=2) tIdCard.grid(row=3, column=2) tTel.grid(row=4, column=2) f3 = Frame(operateFrame) f3.pack(pady=20) bUpdate = Button(f3, text='更新', command=lambda: updateStudent(studentIdVar.get(), studentNameVar.get(), idCardVar.get(), telVar.get())) bDelete = Button(f3, text='删除', command=lambda: deleteStudent(studentIdVar.get())) bUpdate.grid(row=1, column=1) bDelete.grid(row=1, column=2) def updateStudent(studentId, studentName, idCard, tel): try: if not studentId.isdigit(): raise Exception('学号必须为数字!') if len(idCard) != 18: raise Exception('身份证号码必须是18位!') if len(tel) != 11: raise Exception('手机号必须是11位!') # 更新数据库中的学生信息 cursor = cn.cursor() cursor.execute('UPDATE 学生信息表 SET 姓名=?, 身份证号码=?, 手机号=? WHERE 学号=?', (studentName, idCard, tel, studentId)) cn.commit() showinfo('提示', '更新成功!') except Exception as e: showinfo('错误', str(e)) def deleteStudent(studentId): result = askokcancel('确认', '确定要删除该学生信息吗?') if result: # 删除数据库中的学生信息 cursor = cn.cursor() cursor.execute('DELETE FROM 学生信息表 WHERE 学号=?', (studentId,)) cn.commit() showinfo('提示', '删除成功!') searchVar.set('') searchEntry.focus_set()
7.设置批量导入学生信息
def importStudents(): # 要求用户选择一个 Excel 文件 file_path = askopenfilename(filetypes=[('Excel Files', '*.xlsx')]) if file_path: try: # 将 Excel 文件读入 pandas DataFrame 中 df = pd.read_excel(file_path) # 循环访问 DataFrame 中的每一行 for _, row in df.iterrows(): student_id = str(row['学号']) student_name = str(row['姓名']) id_card = str(row['身份证号码']) tel = str(row['手机号']) # 检查数据库中是否已存在学生 cursor = cn.cursor() cursor.execute("SELECT * FROM 学生信息表 WHERE 学号=?", (student_id,)) existing_student = cursor.fetchone() if existing_student: # Student 已存在,跳过导入 continue # 将学生插入数据库 cursor.execute('INSERT INTO 学生信息表 VALUES (?, ?, ?, ?)', (student_id, student_name, id_card, tel)) cn.commit() showinfo('提示', '批量导入成功!') except Exception as e: showinfo('错误', str(e)) else: showinfo('提示', '未选择文件!') # 记录用户操作 logging.info('用户执行了批量导入学生信息')
注意:批量导入信息需要提供Excel 文件,这个时候要下载另一个库:openpyxl。看名字就知道是用于Python打开Excel 文件的库。虽然在程序里面没有直接调用,但是如果没有这个库,在运行时功能时就使用不了。Excel 文件模版如下:
以上的就是学生管理模块功能。
8.设置查看日志:
def viewLog(): # 获取当前工程目录 project_dir = os.getcwd() # 设置日志文件路径 log_file_path = os.path.join(project_dir, '日志文件.txt') # 如果日志文件所在目录不存在,则创建该目录 log_dir = os.path.dirname(log_file_path) if not os.path.exists(log_dir): os.makedirs(log_dir) # 打开日志文件,进行日志记录 # 设置日志记录器 logging.basicConfig(filename='日志文件.txt', level=logging.INFO, format='%(asctime)s - %(message)s') # 创建一个新的窗口 logWindow = Toplevel(root) logWindow.title('日志') # 创建一个文本框,用于显示日志内容 logText = Text(logWindow) logText.pack() # 读取日志文件内容,并将其显示在文本框中 with open('日志文件.txt', 'r') as file: logContent = file.read() logText.insert(END, logContent)
注意:这个日志文件会自动生成在工程目录下,并且记录你每次的操作过程
9.设置关于我们:
def about(): showinfo('关于我们', '本程序由林渊达工作室研发。\n林渊达工作室是一个致力于Python程序研究和人工智能开发等工作室。\n如遇问题可以联系邮箱:linyuanda@linyuanda.com。\n个人博客:https' '://www.cnblogs.com/python120。')
注意:关于我们是我的开发声明,如无必要,最好不要修改,谢谢配合。
以上就是其他模块的功能
10.进入GUI模块:
if __name__ == '__main__': main()
好啦,这样就大功告成啦。
完整代码如下:
from tkinter import * from tkinter.messagebox import askokcancel, showinfo import tkinter.ttk as ttk import pyodbc import os import logging import pandas as pd from tkinter.filedialog import askopenfilename # 连接到 SQL ServerConnect to SQL Server cn = pyodbc.connect('DRIVER={SQL Server};SERVER=(local);DATABASE=学生管理系统;UID=LYD\\lyd;Trusted_Connection=yes') root = Tk() systitle = '学生信息管理系统' # 系统标题 operateFrame = Frame(root) # 功能窗口 operateFrame.pack() def main(): root.geometry('800x600') # 设置窗口初始大小 root.title(systitle) # 设置系统标题 # 创建系统菜单 menubar = Menu(root) # 创建Menu对象menubar,将作为root窗口中的菜单 root.config(menu=menubar) # 将menubar菜单作为root窗口的顶层菜单栏 # menuStudent将作为menubar菜单的子菜单 menuStudent = Menu(menubar, tearoff=0) menuStudent.add_command(label='添加新学生', font=('宋体', 10), command=addStudent) menuStudent.add_command(label='显示全部学生信息', font=('宋体', 10), command=showAllStudent) menuStudent.add_command(label='查找/修改/删除学生信息', font=('宋体', 10), command=checkUpdateStudent) menuStudent.add_command(label='批量导入学生信息', font=('宋体', 10), command=importStudents) # 菜单file添加为menubar的子菜单 menubar.add_cascade(label='学生管理', font=('宋体', 10), menu=menuStudent) menuHelp = Menu(menubar, tearoff=0) # help将作为menubar菜单的子菜单 menuHelp.add_command(label='查看日志', font=('宋体', 10), command=viewLog) menuHelp.add_command(label='关于我们', font=('宋体', 10), command=about) # 菜单help添加为menubar的子菜单 menubar.add_cascade(label='其他', font=('宋体', 10), menu=menuHelp) menubar.add_command(label='退出', font=('宋体', 10), command=root.quit) root.mainloop() def addStudent(): for widget in operateFrame.winfo_children(): # 清空窗口中原有的所有内容 widget.destroy() f1 = Frame(operateFrame) f1.pack() studentIdVar = StringVar() studentNameVar = StringVar() idCardVar = StringVar() telVar = StringVar() lStudentId = Label(f1, text='学号:') lStudentName = Label(f1, text='姓名:') lIdCard = Label(f1, text='身份证号码:') lTel = Label(f1, text='手机号:') tStudentId = Entry(f1, textvariable=studentIdVar) tStudentName = Entry(f1, textvariable=studentNameVar) tIdCard = Entry(f1, textvariable=idCardVar) tTel = Entry(f1, textvariable=telVar) lStudentId.grid(row=1, column=1) lStudentName.grid(row=2, column=1) lIdCard.grid(row=3, column=1) lTel.grid(row=4, column=1) tStudentId.grid(row=1, column=2) tStudentName.grid(row=2, column=2) tIdCard.grid(row=3, column=2) tTel.grid(row=4, column=2) f2 = Frame(operateFrame) f2.pack(pady=20) bReset = Button(f2, text='重置') bSave = Button(f2, text='保存') bReset.grid(row=1, column=1) bSave.grid(row=1, column=2) # 记录用户操作 logging.info('用户执行了添加新学生操作') def reset(): studentIdVar.set('') studentNameVar.set('') idCardVar.set('') telVar.set('') bReset.config(command=reset) def save(): try: id = studentIdVar.get() if not id.isdigit(): raise Exception('学号必须为数字!') name = studentNameVar.get() id_card = idCardVar.get() if len(id_card) != 18: raise Exception('身份证号码必须是18位!') tel = telVar.get() if len(tel) != 11: raise Exception('手机号必须是11位!') # 向数据库发送插入指令 cursor = cn.cursor() cursor.execute('INSERT INTO 学生信息表 VALUES (?, ?, ?, ?)', (id, name, id_card, tel)) cn.commit() showinfo('提示', '保存成功!') except Exception as e: showinfo('错误', str(e)) bSave.config(command=save) def showAllStudent(): # 清空窗口中原有的所有内容 for widget in operateFrame.winfo_children(): widget.destroy() # 创建表格 tree = ttk.Treeview(operateFrame) tree["columns"] = ("学号", "姓名", "身份证号码", "手机号") tree.column("学号", width=100) tree.column("姓名", width=100) tree.column("身份证号码", width=150) tree.column("手机号", width=100) tree.heading("学号", text="学号") tree.heading("姓名", text="姓名") tree.heading("身份证号码", text="身份证号码") tree.heading("手机号", text="手机号") tree.pack(side=LEFT, fill=Y) # 从数据库中获取学生信息 cursor = cn.cursor() cursor.execute("SELECT * FROM 学生信息表") rows = cursor.fetchall() # 在表格中显示学生信息 for row in rows: tree.insert("", "end", values=row) # 记录用户操作 logging.info('用户执行了显示全部学生信息操作') def checkUpdateStudent(): for widget in operateFrame.winfo_children(): widget.destroy() f1 = Frame(operateFrame) f1.pack() searchVar = StringVar() searchLabel = Label(f1, text='请输入学号:') searchEntry = Entry(f1, textvariable=searchVar) searchButton = Button(f1, text='搜索', command=lambda: searchStudent(searchVar.get())) searchLabel.grid(row=1, column=1) searchEntry.grid(row=1, column=2) searchButton.grid(row=1, column=3) def searchStudent(studentId): # 在数据库中搜索学生信息 cursor = cn.cursor() cursor.execute("SELECT * FROM 学生信息表 WHERE 学号=?", (studentId,)) row = cursor.fetchone() # 记录用户操作 logging.info('用户执行了查找/修改/删除学生信息操作') if row: showStudentInfo(row) else: showinfo('提示', '未找到该学生信息!') def showStudentInfo(studentInfo): # 清空窗口中原有的所有内容 for i in operateFrame.winfo_children(): i.destroy() f2 = Frame(operateFrame) f2.pack() studentIdVar = StringVar(value=studentInfo[0]) studentNameVar = StringVar(value=studentInfo[1]) idCardVar = StringVar(value=studentInfo[2]) telVar = StringVar(value=studentInfo[3]) lStudentId = Label(f2, text='学号:') lStudentName = Label(f2, text='姓名:') lIdCard = Label(f2, text='身份证号码:') lTel = Label(f2, text='手机号:') tStudentId = Entry(f2, textvariable=studentIdVar, state='readonly') tStudentName = Entry(f2, textvariable=studentNameVar) tIdCard = Entry(f2, textvariable=idCardVar) tTel = Entry(f2, textvariable=telVar) lStudentId.grid(row=1, column=1) lStudentName.grid(row=2, column=1) lIdCard.grid(row=3, column=1) lTel.grid(row=4, column=1) tStudentId.grid(row=1, column=2) tStudentName.grid(row=2, column=2) tIdCard.grid(row=3, column=2) tTel.grid(row=4, column=2) f3 = Frame(operateFrame) f3.pack(pady=20) bUpdate = Button(f3, text='更新', command=lambda: updateStudent(studentIdVar.get(), studentNameVar.get(), idCardVar.get(), telVar.get())) bDelete = Button(f3, text='删除', command=lambda: deleteStudent(studentIdVar.get())) bUpdate.grid(row=1, column=1) bDelete.grid(row=1, column=2) def updateStudent(studentId, studentName, idCard, tel): try: if not studentId.isdigit(): raise Exception('学号必须为数字!') if len(idCard) != 18: raise Exception('身份证号码必须是18位!') if len(tel) != 11: raise Exception('手机号必须是11位!') # 更新数据库中的学生信息 cursor = cn.cursor() cursor.execute('UPDATE 学生信息表 SET 姓名=?, 身份证号码=?, 手机号=? WHERE 学号=?', (studentName, idCard, tel, studentId)) cn.commit() showinfo('提示', '更新成功!') except Exception as e: showinfo('错误', str(e)) def deleteStudent(studentId): result = askokcancel('确认', '确定要删除该学生信息吗?') if result: # 删除数据库中的学生信息 cursor = cn.cursor() cursor.execute('DELETE FROM 学生信息表 WHERE 学号=?', (studentId,)) cn.commit() showinfo('提示', '删除成功!') searchVar.set('') searchEntry.focus_set() def importStudents(): # 要求用户选择一个 Excel 文件 file_path = askopenfilename(filetypes=[('Excel Files', '*.xlsx')]) if file_path: try: # 将 Excel 文件读入 pandas DataFrame 中 df = pd.read_excel(file_path) # 循环访问 DataFrame 中的每一行 for _, row in df.iterrows(): student_id = str(row['学号']) student_name = str(row['姓名']) id_card = str(row['身份证号码']) tel = str(row['手机号']) # 检查数据库中是否已存在学生 cursor = cn.cursor() cursor.execute("SELECT * FROM 学生信息表 WHERE 学号=?", (student_id,)) existing_student = cursor.fetchone() if existing_student: # Student 已存在,跳过导入 continue # 将学生插入数据库 cursor.execute('INSERT INTO 学生信息表 VALUES (?, ?, ?, ?)', (student_id, student_name, id_card, tel)) cn.commit() showinfo('提示', '批量导入成功!') except Exception as e: showinfo('错误', str(e)) else: showinfo('提示', '未选择文件!') # 记录用户操作 logging.info('用户执行了批量导入学生信息') def viewLog(): # 获取当前工程目录 project_dir = os.getcwd() # 设置日志文件路径 log_file_path = os.path.join(project_dir, '日志文件.txt') # 如果日志文件所在目录不存在,则创建该目录 log_dir = os.path.dirname(log_file_path) if not os.path.exists(log_dir): os.makedirs(log_dir) # 打开日志文件,进行日志记录 # 设置日志记录器 logging.basicConfig(filename='日志文件.txt', level=logging.INFO, format='%(asctime)s - %(message)s') # 创建一个新的窗口 logWindow = Toplevel(root) logWindow.title('日志') # 创建一个文本框,用于显示日志内容 logText = Text(logWindow) logText.pack() # 读取日志文件内容,并将其显示在文本框中 with open('日志文件.txt', 'r') as file: logContent = file.read() logText.insert(END, logContent) def about(): showinfo('关于我们', '本程序由林渊达工作室研发。\n林渊达工作室是一个致力于Python程序研究和人工智能开发等工作室。\n如遇问题可以联系邮箱:linyuanda@linyuanda.com。\n个人博客:https' '://www.cnblogs.com/python120。') if __name__ == '__main__': main()
运行结果如下:
至于各大功能运行情况可以自行尝试。如果有问题欢迎随时提问!