图书管理系统开发教程(小白友好版)
适用对象 :Python 初学者、刚接触面向对象和 GUI 编程的同学
目标:带你从零理解一个基于 PyQt5 的小型图书管理系统架构与实现细节
🧩 一、项目整体结构概览
我们这个系统由以下几个核心模块组成:
| 模块 | 功能 |
|---|---|
model/ |
数据模型(User, Book, Role, Permission) |
dao/ |
数据访问层(Database) |
controller/ |
控制逻辑(用户、图书、权限控制) |
view/ |
用户界面(登录、注册、不同角色主窗口) |
main.py |
程序入口 |
📦 二、数据模型(Model)
1. 角色定义 ------ role.py
python
class Role:
ADMIN = "admin"
TEACHER = "teacher"
STUDENT = "student"
- 这里用类变量模拟"枚举",避免魔法字符串。
- 后续所有判断角色的地方都用
Role.ADMIN而不是"admin",更安全、可读性高。
2. 权限定义 ------ permission.py
python
class Permission:
ADD_BOOK = "add_book"
DELETE_BOOK = "delete_book"
IMPORT_BOOK = "import_book"
EXPORT_BOOK = "export_book"
- 同样是枚举思想,定义系统支持的所有操作权限。
3. 用户模型 ------ user.py
python
class User:
def __init__(self, id, username, role):
self.id = id
self.username = username
self.role = role
- 封装用户基本信息,用于在程序中传递身份。
4. 图书模型 ------ book.py
python
class Book:
def __init__(self, id, title, author, isbn, category):
self.id = id
self.title = title
self.author = author
self.isbn = isbn
self.category = category
- 虽然当前代码中没直接用到
Book类(因为数据库返回的是字典),但保留它为未来扩展打基础。
💾 三、数据访问层(DAO)------ database.py
python
import sqlite3
class Database:
def __init__(self, db_name="library.db"):
self.conn = sqlite3.connect(db_name)
self.conn.row_factory = sqlite3.Row # ← 关键!让结果像字典一样访问
self.init_tables()
def init_tables(self):
# 创建 users 表
self.conn.execute("""
CREATE TABLE IF NOT EXISTS users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE,
password TEXT,
role TEXT
)
""")
# 创建 books 表
self.conn.execute("""
CREATE TABLE IF NOT EXISTS books(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT,
isbn TEXT,
category TEXT
)
""")
self.conn.commit()
def execute(self, sql, params=()):
cursor = self.conn.cursor()
cursor.execute(sql, params)
self.conn.commit()
return cursor
✅ 重点说明:
- 使用 SQLite 内嵌数据库,无需额外安装服务。
row_factory = sqlite3.Row让查询结果可以通过row["username"]方式访问,而不是row[1],极大提升可读性。execute方法统一处理 SQL 执行 + 提交,避免忘记 commit。
🔐 四、用户控制器 ------ user_controller.py
python
import hashlib
from dao.database import Database
from model.user import User
from model.role import Role
class UserController:
def __init__(self):
self.db = Database()
self.ensure_admin() # 确保 admin 用户存在
def hash_password(self, password):
return hashlib.sha256(password.encode()).hexdigest()
def ensure_admin(self):
cursor = self.db.execute("SELECT * FROM users WHERE username=?", ("admin",))
if cursor.fetchone() is None:
self.register("admin", "123456", Role.ADMIN)
def register(self, username, password, role):
if not username or not password:
raise Exception("用户名或密码不能为空")
self.db.execute("""
INSERT INTO users(username, password, role)
VALUES (?, ?, ?)
""", (username, self.hash_password(password), role))
def login(self, username, password):
cursor = self.db.execute("SELECT * FROM users WHERE username=?", (username,))
user = cursor.fetchone()
if user and user["password"] == self.hash_password(password):
return User(user["id"], user["username"], user["role"])
return None
✅ 关键点解析:
- 密码安全 :使用
hashlib.sha256对密码哈希,绝不存明文密码。 - 自动创建管理员 :第一次运行时自动创建
admin / 123456账号,方便测试。 - 登录验证 :比对哈希后的密码,成功则返回
User对象,失败返回None。 - 异常处理:注册时空用户名/密码会抛出异常(后续 UI 会捕获并提示)。
⚠️ 注意:
123456是弱密码,实际项目应要求强密码或首次登录改密。
🛡️ 五、权限管理器 ------ permission_manager.py
python
from model.role import Role
from model.permission import Permission
class PermissionManager:
ROLE_PERMISSIONS = {
Role.ADMIN: [
Permission.ADD_BOOK,
Permission.DELETE_BOOK,
Permission.IMPORT_BOOK,
Permission.EXPORT_BOOK
],
Role.TEACHER: [Permission.ADD_BOOK],
Role.STUDENT: []
}
@classmethod
def has_permission(cls, role, permission):
return permission in cls.ROLE_PERMISSIONS.get(role, [])
✅ 设计亮点:
- 权限配置集中在一个字典里,清晰直观。
- 使用
@classmethod,无需实例化即可调用:PermissionManager.has_permission(...) - 学生没有任何权限,教师只能添加,管理员全有。
📚 六、图书控制器 ------ book_controller.py
python
from dao.database import Database
from controller.permission_manager import PermissionManager
from model.permission import Permission
class BookController:
def __init__(self, user):
self.db = Database()
self.user = user
def add_book(self, title, author, isbn, category):
if not PermissionManager.has_permission(self.user.role, Permission.ADD_BOOK):
raise Exception("没有权限")
self.db.execute("""
INSERT INTO books(title, author, isbn, category)
VALUES (?, ?, ?, ?)
""", (title, author, isbn, category))
def delete_book(self, book_id):
if not PermissionManager.has_permission(self.user.role, Permission.DELETE_BOOK):
raise Exception("没有权限")
self.db.execute("DELETE FROM books WHERE id=?", (book_id,))
def list_books(self):
cursor = self.db.execute("SELECT * FROM books")
return cursor.fetchall()
✅ 权限控制集成:
- 每个操作前先检查权限,无权限则抛出异常。
- 异常会被 UI 捕获并弹窗提示(见后文)。
👤 七、用户界面(View)
1. 登录窗口 ------ login_window.py
python
from PyQt5.QtWidgets import *
from controller.user_controller import UserController
from view.register_window import RegisterWindow
class LoginWindow(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("登录")
self.controller = UserController()
# ... 布局代码 ...
self.user = None
def login(self):
user = self.controller.login(self.edit_user.text(), self.edit_pass.text())
if user:
self.user = user
self.accept() # 关闭对话框并返回 True
else:
QMessageBox.warning(self, "错误", "登录失败")
def open_register(self):
RegisterWindow().exec_() # 模态弹出注册窗口
✅ 要点:
- 继承
QDialog,适合登录/注册这类临时窗口。 accept()表示"成功关闭",main.py中通过if login.exec_():判断是否登录成功。- 密码输入框设置为密文:
self.edit_pass.setEchoMode(QLineEdit.Password)
2. 注册窗口 ------ register_window.py
python
class RegisterWindow(QDialog):
def __init__(self):
super().__init__()
self.combo_role.addItems([Role.TEACHER, Role.STUDENT]) # 只能选教师或学生
def register(self):
self.controller.register(
self.edit_user.text(),
self.edit_pass.text(),
self.combo_role.currentText()
)
QMessageBox.information(self, "成功", "注册成功")
self.accept()
✅ 限制:普通用户不能注册为管理员,防止权限提升。
3. 不同角色主窗口
✅ 学生窗口 ------ student_window.py
- 只有 刷新按钮
- 没有添加/删除按钮(UI 层就隐藏了)
- 即使通过其他方式调用
add_book,也会因权限不足被BookController拦截
✅ 教师窗口 ------ teacher_window.py
- 有 添加、删除、刷新 按钮
- 但删除时会触发权限检查 → 教师无
DELETE_BOOK权限 → 抛出异常 → 弹窗"没有权限"
💡 重要 :这里存在一个 UI 与权限不一致 的问题!
教师界面上显示了"删除"按钮,但点击会报错。更好的做法是:根据权限动态显示按钮。
✅ 管理员窗口 ------ admin_window.py
- 只实现了"添加测试书"功能(硬编码)
- 实际应像教师窗口那样弹出输入框(当前是简化版)
🚀 八、程序入口 ------ main.py
python
import sys
from PyQt5.QtWidgets import QApplication
from view.login_window import LoginWindow
# ... 导入各角色窗口 ...
if __name__ == "__main__":
app = QApplication(sys.argv)
login = LoginWindow()
if login.exec_(): # 如果登录成功
user = login.user
if user.role == Role.ADMIN:
window = AdminWindow(user)
elif user.role == Role.TEACHER:
window = TeacherWindow(user)
else:
window = StudentWindow(user)
window.show()
sys.exit(app.exec_())
✅ 流程:
- 启动应用
- 弹出登录窗口
- 登录成功 → 根据角色打开对应主窗口
- 进入事件循环
🔍 九、潜在问题与改进建议
❗ 1. 教师界面显示了"删除"按钮但无权限
-
原因:UI 未根据权限动态调整
-
修复建议 :
python# 在 TeacherWindow.__init__ 中 if PermissionManager.has_permission(user.role, Permission.DELETE_BOOK): btn_layout.addWidget(self.btn_delete)
❗ 2. 管理员窗口功能简陋
- 当前
add_book是硬编码的,应改为弹窗输入。
❗ 3. 密码强度弱
admin默认密码123456不安全,应首次登录强制修改。
✅ 4. 优点总结
- 分层清晰(Model / DAO / Controller / View)
- 权限控制集中、可扩展
- 使用 SQLite,零配置运行
- 代码简洁,适合教学
🧪 十、如何运行?
-
安装依赖:
bashpip install PyQt5 -
将所有
.py文件放在同一目录 -
运行:
bashpython main.py -
首次运行会自动创建
library.db和admin账号
📝 结语
这个小项目虽然简单,但涵盖了:
- 面向对象编程(OOP)
- MVC 架构思想
- 数据库操作(SQLite)
- GUI 开发(PyQt5)
- 权限控制设计
- 密码安全基础
非常适合 Python 初学者作为练手项目!你可以在此基础上:
- 添加"借阅/归还"功能
- 实现图书搜索
- 支持 Excel 导入导出(利用已有
IMPORT_BOOK/EXPORT_BOOK权限)
记住:好的代码 = 清晰的结构 + 明确的职责 + 安全的实践。