目录
- 1. 项目概述
- 2. 环境准备与数据库设计
- 2.1 所需环境
- 2.2 数据库表结构
- 3. 核心代码实现
- 3.1 数据库连接配置
- 3.2 主程序与菜单
- 3.3 查询功能实现
- 3.3.1 查询全部学生信息
- 3.3.2 根据学号查询学生信息
- 3.3.3 搜索学生信息
- 3.4 添加学生信息
- 3.5 修改学生信息
- 3.6 删除学生信息(软删除)
- 3.7 主循环与菜单选择
- 4. 系统特点与优化建议
- 4.1 系统特点
- 4.2 优化建议
- 5. 总结
- 5.1 完整代码文件
- 6. 代码优化
- 6.1 优化思路分析
- 6.1.1 功能分离与代码复用
- 6.1.2 动态字段修改
- 6.2 优化代码详解
- 6.2.1 新增的辅助函数
- 6.2.2 重构后的主函数
- 6.3 优化带来的好处
- 6.3.1 代码可维护性提升
- 6.3.2 用户体验改善
- 6.3.3 扩展性增强
- 6.4 进一步优化建议
- 6.4.1 输入验证增强
- 6.4.2 异常处理完善
- 6.4.3 支持批量修改
- 6.5 总结
- 6.6 优化后的代码文件
- 6.1 优化思路分析
1. 项目概述
本文将介绍一个基于 Python 和 MySQL 的简单学生信息管理系统。该系统实现了学生信息的增删改查(CRUD)功能,采用命令行交互方式,适合初学者学习 Python 数据库编程和基础系统开发。
系统主要功能包括:
- 查询全部学生信息
- 添加新学生
- 修改学生信息
- 删除学生(软删除)
- 按学号搜索学生
2. 环境准备与数据库设计
2.1 所需环境
- Python 3.x
- PyMySQL 库(pip install pymysql)
- MySQL 数据库
2.2 数据库表结构
首先创建数据库和表结构:
CREATE DATABASE IF NOT EXISTS abc;
USE abc;
CREATE TABLE `s1` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '编号',
`s_name` varchar(20) NOT NULL COMMENT '姓名',
`age` int NOT NULL COMMENT '年龄',
`sex` enum('男','女','未知') DEFAULT '未知' COMMENT '性别',
`s_sno` char(12) NOT NULL COMMENT '学号',
`tel` char(11) NOT NULL COMMENT '手机号',
`start_time` date DEFAULT (curdate()) COMMENT '入学时间',
`status` enum('在读','毕业') DEFAULT '在读' COMMENT '状态',
`id_card` char(18) DEFAULT NULL COMMENT '身份证号',
PRIMARY KEY (`id`),
UNIQUE KEY `s_name` (`s_name`),
UNIQUE KEY `s_sno` (`s_sno`),
KEY `name` (`s_name`),
KEY `name_age` (`s_name`,`age`),
FULLTEXT KEY `name_fulltext` (`s_name`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
3. 核心代码实现
3.1 数据库连接配置
import pymysql
# 创建数据库连接
db = pymysql.connect(
host="localhost",
user="root",
password="123456",
database="abc"
)
# 创建游标对象,采用字典模式
# 默认是元组模式,采用字典模式后可以通过 data['name'] 等方式取值
cursor = db.cursor(cursor=pymysql.cursors.DictCursor)
3.2 主程序与菜单
# 主程序提示
tip = """
================================
欢迎使用【学生信息管理系统】
====================================
【1】查询全部学生
【2】添加学生
【3】修改学生
【4】删除学生
【5】搜索学生
【6】退出
请输入:"""
3.3 查询功能实现
3.3.1 查询全部学生信息
def seachAll():
sql = "select * from s1 where status = '在读'"
cursor.execute(sql)
data = cursor.fetchall()
print("编号 姓 名 \\t学 号\\t\\t 年龄\\t 性别\\t 联系方式\\t\\t\\t 身份证号")
for item in data:
print(f"{item['id']}\\t{item['s_name']}\\t\\t{item['s_sno']}\\t\\t{item['age']}\\t\\t{item['sex']}\\t\\t{item['tel']}\\t\\t\\t{item['id_card']}")
3.3.2 根据学号查询学生信息
def seachBySno(sno):
sql = "select * from s1 where status = '在读' and s_sno = %s limit 1"
cursor.execute(sql, (sno,)) # 元组,(sno,)是为了匹配SQL语句中字段,同时确保类型为元组
return cursor.fetchone()
3.3.3 搜索学生信息
def seach():
print("==========搜索学生信息=========")
sno = input("请输入学生学号:")
data = seachBySno(sno)
if data:
print(data)
else:
print("没有此学生")
3.4 添加学生信息
def addStudent():
print("==========添加学生信息=========")
sname = input("请输入学生姓名:")
sno = input("请输入学生学号:")
data = seachBySno(sno)
if data:
print("学号已存在")
return # 返回退出,下面的逻辑不执行
age = int(input("请输入学生年龄:")) # 年龄字段与数据库字段类型一致
if age <= 0 or age > 130:
print("年龄输入错误")
else:
sex = input("请输入学生性别:")
tel = input("请输入学生联系方式:")
# idCard = input("请输入学生身份证号:")
sql = "insert into s1(s_name,age,sex,s_sno,tel) values (%s,%s,%s,%s,%s)"
values = (sname, age, sex, sno, tel) # 元组,注意顺序与SQL语句中字段顺序一致
cursor.execute(sql, values)
db.commit()
if cursor.rowcount == 1:
print(f"添加{sname}成功")
else:
print(f"添加{sname}失败")
3.5 修改学生信息
def updateStudent():
print("==========修改学生信息=========")
sno = input("请输入学生学号:")
if seachBySno(sno):
sname = input("请输入学生姓名:")
age = int(input("请输入学生年龄:"))
if age <= 0 or age > 130:
print("年龄输入错误")
return # 返回退出,下面的逻辑不执行
sex = input("请输入学生性别:")
tel = input("请输入学生联系方式:")
sql = "update s1 set s_name = %s,age = %s,sex = %s,tel = %s where s_sno = %s"
values = (sname, age, sex, tel, sno)
cursor.execute(sql, values)
db.commit()
if cursor.rowcount == 0 or cursor.rowcount == 1:
print("修改成功")
else:
print("修改失败")
else:
print("没有此学生")
3.6 删除学生信息(软删除)
def deleteStudent():
print("==========删除学生信息=========")
sno = input("请输入学生学号:")
data = seachBySno(sno)
if data:
print(data)
confirm = input("确定删除吗?y/n:")
if confirm == "y" or confirm == "Y":
sql = "update s1 set status = '毕业' where s_sno = %s"
cursor.execute(sql, (sno,))
db.commit()
print("删除成功!")
else:
print("取消删除!")
else:
print("没有此学生")
3.7 主循环与菜单选择
while True:
print(tip)
choice = input().strip()
match choice:
case "1":
print("==========查询全部学生=========")
seachAll()
case "2":
print("==========添加学生信息=========")
addStudent()
case "3":
print("==========修改学生信息=========")
updateStudent()
case "4":
print("==========删除学生信息=========")
deleteStudent()
case "5":
print("==========搜索学生===========")
seach()
case "6":
print("==========退出===========")
break
4. 系统特点与优化建议
4.1 系统特点
4.2 优化建议
5. 总结
本系统展示了如何使用 Python 和 MySQL 构建一个简单的学生信息管理系统。通过这个项目,可以学习到:
- Python 连接 MySQL 数据库的基本操作
- 使用 PyMySQL 库执行 SQL 语句
- 实现基本的 CRUD 功能
- 数据库表设计和约束的使用
- 命令行交互程序的设计
代码结构清晰,适合初学者学习和扩展。读者可以根据自己的需求进一步优化和完善系统功能。
5.1完整代码文件
import pymysql
# 创建数据库连接
db = pymysql.connect(
host="localhost",
user="root",
password="123456",
database="abc"
)
# 创建游标对象 可以实现 增删改查 cursor=pymysql.cursors.DictCursor采用字典模式,
# 默认是元组模式,后续可以data['name']等进行取值
cursor = db.cursor(cursor=pymysql.cursors.DictCursor)
from project.database import db,cursor
# 主程序提示
tip = """
================================欢迎使用【学生信息管理系统】====================================
【1】查询全部学生
【2】添加学生
【3】修改学生
【4】删除学生
【5】搜索学生
【6】退出
请输入:
"""
# 查询全部学生信息
def seachAll():
sql ="select * from s1 where status = '在读'"
cursor.execute(sql)
data = cursor.fetchall()
print("编号 姓 名 \\t学 号\\t\\t 年龄\\t 性别\\t 联系方式\\t\\t\\t 身份证号")
for item in data:
print(f"{item['id']}\\t{item['s_name']}\\t\\t{item['s_sno']}\\t\\t{item['age']}\\t\\t{item['sex']}\\t\\t{item['tel']}\\t\\t\\t{item['id_card']}")
# 搜索学生信息
# def seachOne():
# sql ="select * from s1 where status = '在读' and s_name = %s limit 1" # limit 1避免获取多条数据以及浪费时间
# sname = input("请输入学生姓名:")
# cursor.execute(sql,sname)
# data = cursor.fetchone()
# print("编号 姓 名 学 号 年龄 性别 联系方式 身份证号")
# print(data['id'],data['s_name'],data['s_sno'],data['age'],data['sex'],data['tel'],data['id_card'])。
# 根据学号查询学生信息
def seachBySno(sno):
sql = "select * from s1 where status = '在读' and s_sno = %s limit 1"
cursor.execute(sql,(sno,)) # 元组,(sno,)是为了匹配SQL语句中字段,同时确保类型为元组,而不是原本的类型
return cursor.fetchone()
# 查询学生信息
# 查询学生信息
def seach():
print("==========搜索学生信息=========")
sno = input("请输入学生学号:")
data = seachBySno(sno)
if data:
print(data)
else:
print("没有此学生")
# 添加学生信息
def addStudent():
print("==========添加学生信息=========")
sname = input("请输入学生姓名:")
sno = input("请输入学生学号:")
data = seachBySno(sno)
if data:
print("学号已存在")
return # 返回退出,下面的逻辑不执行
age = int(input("请输入学生年龄:")) # 年龄字段与数据库字段类型一致,匹配数据库字段类型
if age<=0 or age>130:
print("年龄输入错误")
else:
sex = input("请输入学生性别:")
tel = input("请输入学生联系方式:")
#idCard = input("请输入学生身份证号:")
sql = "insert into s1(s_name,age,sex,s_sno,tel) values (%s,%s,%s,%s,%s)"
values = (sname, age, sex, sno, tel) # 元组,注意顺序与SQL语句中字段顺序一致
cursor.execute(sql, values)
db.commit()
if(cursor.rowcount == 1):
print(f"添加{sname}成功")
else:
print(f"添加{sname}失败")
# 删除学生信息——-软删除
def deleteStudent():
print("==========删除学生信息=========")
sno = input("请输入学生学号:")
data = seachBySno(sno)
if data:
print(data)
confirm = input("确定删除吗?y/n:")
if confirm == "y" or confirm == "Y":
sql = "update s1 set status = '毕业' where s_sno = %s"
cursor.execute(sql,(sno,))
db.commit()
print("删除成功!")
else:
print("取消删除!")
else:
print("没有此学生")
# 修改学生信息
def updateStudent():
print("==========修改学生信息=========")
sno = input("请输入学生学号:")
if seachBySno(sno):
sname = input("请输入学生姓名:")
age = int(input("请输入学生年龄:"))
if age<=0 or age>130:
print("年龄输入错误")
return # 返回退出,下面的逻辑不执行
sex = input("请输入学生性别:")
tel = input("请输入学生联系方式:")
sql = "update s1 set s_name = %s,age = %s,sex = %s,tel = %s where s_sno = %s"
values = (sname, age, sex, tel, sno)
cursor.execute(sql, values)
db.commit()
if(cursor.rowcount == 0 or cursor.rowcount == 1):
print("修改成功")
else:
print("修改失败")
else:
print("没有此学生")
while True:
print(tip)
choice = input().strip()
match choice:
case"1":
print("==========查询全部学生=========")
seachAll()
case"2":
print("==========添加学生信息=========")
addStudent()
case"3":
print("==========修改学生信息=========")
updateStudent()
case"4":
print("==========删除学生信息=========")
deleteStudent()
case"5":
print("==========搜索学生===========")
seach()
case"6":
print("==========退出==============")
break
case _:
print("输入错误,请重新输入:")
6.代码优化
6.1 优化思路分析
在原始代码的基础上,我们对修改学生信息功能进行了重构和优化,主要改进点如下:
6.1.1 功能分离与代码复用
原始代码中,updateStudent() 函数负责所有修改逻辑,包括:
- 学号验证
- 用户输入
- SQL 语句构建
- 数据库更新
- 结果反馈
优化后的代码将核心的数据库更新操作提取为独立的 updateStudentChoice() 函数,实现了单一职责原则。
6.1.2 动态字段修改
原始代码只能同时修改所有字段(姓名、年龄、性别、联系方式),而优化后的代码允许用户选择要修改的特定字段,提高了系统的灵活性和用户体验。
6.2 优化代码详解
6.2.1 新增的辅助函数
# 修改学生信息的选择方法
def updateStudentChoice(data, file, sno):
sql = f"update s1 set {file} = %s where s_sno = %s" # %s为占位符,这里使用{file}来代替实际字段名
cursor.execute(sql, (data, sno))
db.commit()
if (cursor.rowcount == 0 or cursor.rowcount == 1):
print("修改成功")
else:
print("修改失败")
优化点分析:
参数化设计:函数接收三个参数:
- data:要更新的新值
- file:数据库字段名
- sno:学生学号(作为更新条件)
动态 SQL 构建:使用 f-string 动态构建 SQL 语句,{file} 会根据传入的字段名动态替换
简化逻辑:只执行单一的更新操作,逻辑更清晰
6.2.2 重构后的主函数
# 修改学生信息(可选择)————————-代码优化2——提炼公共信息到方法里
def updateStudent():
print("==========修改学生信息=========")
sno = input("请输入学生学号:")
if seachBySno(sno):
nums = input("请输入修改的字段:1.姓名 2.年龄 3.性别 ")
filds = ["s_name", "age", "sex"]
values = ['姓名', '年龄', '性别']
file = filds[int(nums)–1]
if nums in ['1', '2', '3']:
data = input(f"请输入学生{values[int(nums)–1]}:")
updateStudentChoice(data, file, sno)
else:
print("输入错误")
else:
print("没有此学生")
优化点分析:
菜单化选择:提供清晰的字段选择菜单(1.姓名 2.年龄 3.性别)
映射关系设计:
- filds 列表:存储数据库字段名
- values 列表:存储用户友好的显示名称
- 通过索引建立两个列表的对应关系
输入验证:检查用户输入是否在有效范围内(‘1’, ‘2’, ‘3’)
函数调用:将具体的更新操作委托给 updateStudentChoice() 函数
6.3 优化带来的好处
6.3.1 代码可维护性提升
- 分离关注点:updateStudent() 负责用户交互和输入验证,updateStudentChoice() 负责数据库操作
- 减少重复代码:如果需要添加新的可修改字段,只需扩展 filds 和 values 列表
- 易于测试:每个函数功能单一,便于单元测试
6.3.2 用户体验改善
- 选择性修改:用户可以选择只修改特定字段,无需重新输入所有信息
- 操作更灵活:避免了不必要的重复输入
- 错误减少:减少了因输入多个字段可能导致的错误
6.3.3 扩展性增强
# 未来可以轻松扩展更多字段
filds = ["s_name", "age", "sex", "tel", "id_card"]
values = ['姓名', '年龄', '性别', '联系方式', '身份证号']
# 只需修改这两个列表,无需改动核心逻辑
6.4 进一步优化建议
6.4.1 输入验证增强
# 可以添加更严格的输入验证
def validate_age(age_str):
try:
age = int(age_str)
if 0 < age <= 130:
return age
else:
return None
except ValueError:
return None
def validate_sex(sex_str):
return sex_str if sex_str in ['男', '女', '未知'] else None
6.4.2 异常处理完善
def updateStudentChoice(data, file, sno):
try:
sql = f"update s1 set {file} = %s where s_sno = %s"
cursor.execute(sql, (data, sno))
db.commit()
if cursor.rowcount == 1:
print("修改成功")
return True
else:
print("未找到对应记录或数据未变化")
return False
except Exception as e:
print(f"修改失败: {e}")
db.rollback()
return False
6.4.3 支持批量修改
def updateMultipleFields(sno, updates_dict):
"""批量修改多个字段"""
if not updates_dict:
return False
set_clause = ", ".join([f"{field} = %s" for field in updates_dict.keys()])
values = list(updates_dict.values()) + [sno]
sql = f"update s1 set {set_clause} where s_sno = %s"
# … 执行更新
6.5 总结
本次优化主要实现了:
这种优化模式不仅适用于学生信息管理系统,也可以应用到其他需要类似 CRUD 操作的管理系统中。通过合理的函数拆分和参数化设计,可以显著提高代码的可维护性和用户体验。
6.6优化后的代码文件
from project.database import db,cursor
# 主程序提示
tip = """
================================欢迎使用【学生信息管理系统】====================================
【1】查询全部学生
【2】添加学生
【3】修改学生
【4】删除学生
【5】搜索学生
【6】退出
请输入:
"""
# 查询全部学生信息
def seachAll():
sql ="select * from s1 where status = '在读'"
cursor.execute(sql)
data = cursor.fetchall()
print("编号 姓 名 \\t学 号\\t\\t 年龄\\t 性别\\t 联系方式\\t\\t\\t 身份证号")
for item in data:
print(f"{item['id']}\\t{item['s_name']}\\t\\t{item['s_sno']}\\t\\t{item['age']}\\t\\t{item['sex']}\\t\\t{item['tel']}\\t\\t\\t{item['id_card']}")
# 根据学号查询学生信息
def seachBySno(sno):
sql = "select * from s1 where status = '在读' and s_sno = %s limit 1"
cursor.execute(sql,(sno,)) # 元组,(sno,)是为了匹配SQL语句中字段,同时确保类型为元组,而不是原本的类型
return cursor.fetchone()
# 查询学生信息
def seach():
print("==========搜索学生信息=========")
sno = input("请输入学生学号:")
data = seachBySno(sno)
if data:
print(data)
else:
print("没有此学生")
# 添加学生信息
def addStudent():
print("==========添加学生信息=========")
sname = input("请输入学生姓名:")
sno = input("请输入学生学号:")
data = seachBySno(sno)
if data:
print("学号已存在")
return # 返回退出,下面的逻辑不执行
age = int(input("请输入学生年龄:")) # 年龄字段与数据库字段类型一致,匹配数据库字段类型
if age<=0 or age>130:
print("年龄输入错误")
else:
sex = input("请输入学生性别:")
tel = input("请输入学生联系方式:")
#idCard = input("请输入学生身份证号:")
sql = "insert into s1(s_name,age,sex,s_sno,tel) values (%s,%s,%s,%s,%s)"
values = (sname, age, sex, sno, tel) # 元组,注意顺序与SQL语句中字段顺序一致
cursor.execute(sql, values)
db.commit()
if(cursor.rowcount == 1):
print(f"添加{sname}成功")
else:
print(f"添加{sname}失败")
# 删除学生信息——-软删除
def deleteStudent():
print("==========删除学生信息=========")
sno = input("请输入学生学号:")
data = seachBySno(sno)
if data:
print(data)
confirm = input("确定删除吗?y/n:")
if confirm == "y" or confirm == "Y":
sql = "update s1 set status = '毕业' where s_sno = %s"
cursor.execute(sql,(sno,))
db.commit()
print("删除成功!")
else:
print("取消删除!")
else:
print("没有此学生")
# 修改学生信息的选择方法
def updateStudentChoice(data,file,sno):
sql = f"update s1 set {file} = %s where s_sno = %s" # %s为占位符,这里使用{file}来代替实际字段名
cursor.execute(sql, (data,sno))
db.commit()
if (cursor.rowcount == 0 or cursor.rowcount == 1):
print("修改成功")
else:
print("修改失败")
# 修改学生信息(可选择)————————-代码优化2——提炼公共信息到方法里
def updateStudent():
print("==========修改学生信息=========")
sno = input("请输入学生学号:")
if seachBySno(sno):
nums = input("请输入修改的字段:1.姓名 2.年龄 3.性别 ")
filds = ["s_name","age","sex"]
values = ['姓名','年龄', '性别']
file = filds[int(nums)–1]
if nums in ['1','2','3']:
data = input(f"请输入学生{values[int(nums)–1]}:")
updateStudentChoice(data, file, sno)
else:
print("输入错误")
else:
print("没有此学生")
while True:
print(tip)
choice = input().strip()
match choice:
case"1":
print("==========查询全部学生=========")
seachAll()
case"2":
print("==========添加学生信息=========")
addStudent()
case"3":
print("==========修改学生信息=========")
updateStudent()
case"4":
print("==========删除学生信息=========")
deleteStudent()
case"5":
print("==========搜索学生===========")
seach()
case"6":
print("==========退出==============")
break
case _:
print("输入错误,请重新输入:")




