目录
- [1. 项目概述](#1. 项目概述)
- [2. 环境准备与数据库设计](#2. 环境准备与数据库设计)
- [2.1 所需环境](#2.1 所需环境)
- [2.2 数据库表结构](#2.2 数据库表结构)
- [3. 核心代码实现](#3. 核心代码实现)
- [3.1 数据库连接配置](#3.1 数据库连接配置)
- [3.2 主程序与菜单](#3.2 主程序与菜单)
- [3.3 查询功能实现](#3.3 查询功能实现)
- [3.3.1 查询全部学生信息](#3.3.1 查询全部学生信息)
- [3.3.2 根据学号查询学生信息](#3.3.2 根据学号查询学生信息)
- [3.3.3 搜索学生信息](#3.3.3 搜索学生信息)
- [3.4 添加学生信息](#3.4 添加学生信息)
- [3.5 修改学生信息](#3.5 修改学生信息)
- [3.6 删除学生信息(软删除)](#3.6 删除学生信息(软删除))
- [3.7 主循环与菜单选择](#3.7 主循环与菜单选择)
- [4. 系统特点与优化建议](#4. 系统特点与优化建议)
- [4.1 系统特点](#4.1 系统特点)
- [4.2 优化建议](#4.2 优化建议)
- [5. 总结](#5. 总结)
- [5.1 完整代码文件](#5.1 完整代码文件)
- [6. 代码优化](#6. 代码优化)
- [6.1 优化思路分析](#6.1 优化思路分析)
- [6.1.1 功能分离与代码复用](#6.1.1 功能分离与代码复用)
- [6.1.2 动态字段修改](#6.1.2 动态字段修改)
- [6.2 优化代码详解](#6.2 优化代码详解)
- [6.2.1 新增的辅助函数](#6.2.1 新增的辅助函数)
- [6.2.2 重构后的主函数](#6.2.2 重构后的主函数)
- [6.3 优化带来的好处](#6.3 优化带来的好处)
- [6.3.1 代码可维护性提升](#6.3.1 代码可维护性提升)
- [6.3.2 用户体验改善](#6.3.2 用户体验改善)
- [6.3.3 扩展性增强](#6.3.3 扩展性增强)
- [6.4 进一步优化建议](#6.4 进一步优化建议)
- [6.4.1 输入验证增强](#6.4.1 输入验证增强)
- [6.4.2 异常处理完善](#6.4.2 异常处理完善)
- [6.4.3 支持批量修改](#6.4.3 支持批量修改)
- [6.5 总结](#6.5 总结)
- [6.6 优化后的代码文件](#6.6 优化后的代码文件)
- [6.1 优化思路分析](#6.1 优化思路分析)
1. 项目概述
本文将介绍一个基于 Python 和 MySQL 的简单学生信息管理系统。该系统实现了学生信息的增删改查(CRUD)功能,采用命令行交互方式,适合初学者学习 Python 数据库编程和基础系统开发。
系统主要功能包括:
- 查询全部学生信息
- 添加新学生
- 修改学生信息
- 删除学生(软删除)
- 按学号搜索学生
2. 环境准备与数据库设计
2.1 所需环境
- Python 3.x
- PyMySQL 库(
pip install pymysql) - MySQL 数据库
2.2 数据库表结构
首先创建数据库和表结构:
sql
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 数据库连接配置
python
import pymysql
# 创建数据库连接
db = pymysql.connect(
host="localhost",
user="root",
password="123456",
database="abc"
)
# 创建游标对象,采用字典模式
# 默认是元组模式,采用字典模式后可以通过 data['name'] 等方式取值
cursor = db.cursor(cursor=pymysql.cursors.DictCursor)
3.2 主程序与菜单
python
# 主程序提示
tip = """
================================
欢迎使用【学生信息管理系统】
====================================
【1】查询全部学生
【2】添加学生
【3】修改学生
【4】删除学生
【5】搜索学生
【6】退出
请输入:"""
3.3 查询功能实现
3.3.1 查询全部学生信息
python
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 根据学号查询学生信息
python
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 搜索学生信息
python
def seach():
print("==========搜索学生信息=========")
sno = input("请输入学生学号:")
data = seachBySno(sno)
if data:
print(data)
else:
print("没有此学生")
3.4 添加学生信息
python
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 修改学生信息
python
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 删除学生信息(软删除)
python
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 主循环与菜单选择
python
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 系统特点
- 软删除设计:删除操作实际上是将学生状态改为"毕业",保留了历史数据
- 输入验证:对年龄进行了范围验证(0-130岁)
- 唯一性约束:学号和姓名在数据库层面设置了唯一约束
- 字典游标 :使用
pymysql.cursors.DictCursor方便数据访问
4.2 优化建议
- 异常处理:添加数据库操作异常处理(try-except)
- 密码安全:数据库密码不应硬编码在代码中
- 功能扩展:可添加批量导入导出、统计报表等功能
- 界面优化:可考虑使用 GUI 界面(如 Tkinter)替代命令行
5. 总结
本系统展示了如何使用 Python 和 MySQL 构建一个简单的学生信息管理系统。通过这个项目,可以学习到:
- Python 连接 MySQL 数据库的基本操作
- 使用 PyMySQL 库执行 SQL 语句
- 实现基本的 CRUD 功能
- 数据库表设计和约束的使用
- 命令行交互程序的设计
代码结构清晰,适合初学者学习和扩展。读者可以根据自己的需求进一步优化和完善系统功能。
5.1完整代码文件
python
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)
python
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 新增的辅助函数
python
# 修改学生信息的选择方法
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 重构后的主函数
python
# 修改学生信息(可选择)-------------------------代码优化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 扩展性增强
python
# 未来可以轻松扩展更多字段
filds = ["s_name", "age", "sex", "tel", "id_card"]
values = ['姓名', '年龄', '性别', '联系方式', '身份证号']
# 只需修改这两个列表,无需改动核心逻辑
6.4 进一步优化建议
6.4.1 输入验证增强
python
# 可以添加更严格的输入验证
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 异常处理完善
python
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 支持批量修改
python
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优化后的代码文件
python
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("输入错误,请重新输入:")