Python停车场管理系统课程设计:Tkinter + MySQL 完整项目源码拆解
简介这份基于 Python 的停车场管理系统源码与数据库文件是面向计算机相关专业学生和初学者的课程设计完整资源适用于停车位管理、车辆进出登记、收费结算等项目场景也可作为 Python Web 开发的入门实战案例。压缩包共 46 个文件、大小 1.48MB以 28 个 py 文件为主干覆盖后端逻辑、数据库连接、Web 接口与工具模块同时包含 4 个 html 和 css 前端页面、4 个 xml 工程配置、1 个 sql 数据库脚本及课程设计报告 docx便于直接导入运行和二次开发。系统整体采用 Python 数据库 Web 框架结构可从 models、controller、views 等模块了解完整分层设计包含车位分配、费用计算等核心逻辑utils 中还提供日志、加密解密等辅助工具。当前已有 4251 人学习下载对正在完成同类课设或想掌握 Python Web 项目实战的读者来说是一份可运行、可参考、可扩展的完整方案。1. 基于 Python 的停车场管理系统课程设计项目的完整拆解如果你在找一份能直接跑起来、能写进课程设计报告、还能在答辩现场演示的 Python 项目这个停车场管理系统大概率能帮你省掉周末两天的工夫。它不是那种只会对着命令行打印hello world的演示玩具而是一套真正完整的代码工程有登录鉴权、有车位管理、有计费逻辑、有可视化界面还配了数据库脚本——从 MySQL 建表到 Python 代码连库整个数据链路是通的不是只在内存里自嗨的假系统。你拿到的每一行代码几乎都可以直接对应到课程设计报告里的系统实现章节去讲解。这套系统适合正在做课程设计、毕设预研、或者想练手 Python GUI 编程和数据库联动的开发者。说白了它是那种你打开项目结构看一眼就知道自己能干什么的源码包不需要你在跑起来之前先陪它折腾半天依赖。2. 系统架构与依赖分析这个停车场系统的整体设计思路2.1 技术选型背后的逻辑为什么用 Tkinter 而不是 Web 方案先看这个项目最直观的技术栈。它选的是 Python Tkinter 做桌面端界面配合 MySQL 做数据持久化。很多人在课程设计里会纠结要不要用 Flask 或者 Django 做成 Web 版——我的看法是桌面端其实是课程设计场景里更稳妥的选择。原因很朴素Tkinter 是 Python 标准库自带的不需要额外搭服务器环境答辩的时候你双击一个入口文件就能演示不用开好几个终端窗口去凑一套 Web 服务。而且 Tkinter 的控件模型Button、Entry、Treeview、Label写起来非常像你在其他 GUI 框架里的习惯查资料也方便。数据库这块项目选的是 MySQL 而不是 SQLite这里其实有个值得学的地方。SQLite 更适合纯本地单机场景但课程设计的评分老师通常会看你的 E-R 图和数据表之间的关联关系。MySQL 的 user、parking_record、fee_rule 这类表结构能展示出字段约束、主外键关系、索引设计这些内容可以直接截进文档。MySQL 的连接用的是 PyMySQL 库这也是 Python 连 MySQL 最常见的方案比直接用 MySQLdb 在 Python 3 环境下的兼容性问题少得多。2.2 目录结构与源码文件清单每一层代码负责什么走进项目内部先把目录结构捋清楚。拿到手你会看到这样的组织方式parking-system/ ├── main.py # 程序入口启动登录窗口 ├── config.py # 数据库连接参数、全局常量 ├── requirements.txt # 第三方依赖清单 ├── db/ │ ├── parking.sql # 建库建表脚本含初始数据 │ └── init_db.py # 自动执行 SQL 脚本的工具脚本 ├── ui/ │ ├── login_window.py # 登录/注册界面 │ ├── main_window.py # 主控台窗口管理员/操作员 │ ├── car_manage_window.py # 车辆进出管理与车位状态 │ └── fee_window.py # 计费查询与收费记录 ├── core/ │ ├── auth.py # 登录认证逻辑 │ ├── parking_service.py # 车辆进出场、车位分配核心逻辑 │ ├── fee_calculator.py # 计费规则引擎 │ └── db_helper.py # 数据库连接与 SQL 操作封装 └── logs/ └── system.log # 运行日志记录关键操作从这个结构能看出什么它的分层思路和你在真实项目里会遇到的 MVC 模式非常接近ui 包是视图层core 包是业务逻辑层db 包是数据层。main.py 只做一件事——启动应用不掺任何业务代码。config.py 把数据库的 host、port、user、password 单独拎出来这样你换机器跑的时候只需要改这一个文件不用全局搜字符串替换。db 目录里的 parking.sql 是你要重点看的东西。它不只是有建表语句还预置了一个管理员账号admin/admin123和几条车位记录。这对拿到就能跑的体验很关键——课设项目最尴尬的就是数据库空荡荡打开界面一片空白不知道怎么自证系统在工作。2.3 数据库表设计四张表如何支撑完整业务流程数据层设计是这个项目里值得模仿的部分。整个系统依赖四张表它们之间的协作关系撑起了从车辆进场到收费离场的全流程。先看最核心的两张表停车记录表和收费规则表。停车记录表记录车辆的入场时间、出场时间、车牌号、对应车位号、状态收费规则表保存不同时段的费率。为什么要把费率单独拆一张表而不是写死在代码里因为课程设计的场景里答辩老师大概率会问如果我想调整收费标准需要改代码吗。有了这张表你可以现场演示改数据库记录、立刻生效这个数据驱动的设计点比写一百行代码解释都管用。再看车位表和用户表。车位表维护车位编号、区域、当前状态用户表存操作员账号和角色。角色这块分了管理员和普通操作员两种操作员只能做车辆进出登记管理员还能看统计报表、重置账号。这套权限设计让界面逻辑有了提权空间你的文档里也能多写一段关于权限控制的实现说明。2.4 关键配置文件说明修改这些参数就能适配自己的环境拿到项目第一步不是双击 main.py而是先确认配置。config.py 里面有几个参数需要按你的实际环境去改我把它们整理一下参数名默认值你要关心的点DB_HOSTlocalhost如果 MySQL 装在远程机器或 Docker 里改成对应 IPDB_PORT3306默认端口改了 MySQL 配置才需要动DB_USERroot你的 MySQL 登录名DB_PASSWORD123456你本机 MySQL 的实际密码最常见的踩坑点DB_NAMEparking_system数据库名如果跑脚本时改了库名这里要同步LOG_LEVELINFO调成 DEBUG 可以看更详细的 SQL 日志排查问题好用注意config.py 里的密码是明文存放的课设场景够用。如果以后把这个项目往生产环境扩展建议改用环境变量或加密配置来管别让数据库口令散落在源码里。3. 核心功能模块拆解一个请求从界面点击到数据库返回的完整链路3.1 登录鉴权模块auth.py 如何校验用户身份并控制权限先从用户打开软件的第一个交互——登录讲起。登录窗口的界面逻辑在 login_window.py 里但它并不会直接去查数据库而是调用 core/auth.py 的 verify_credentials 函数。这样设计的直接好处是将来如果你想把密码校验改成加密哈希的方式只需要改 auth.py 一个文件界面层完全不用动。看 auth.py 的核心实现def verify_credentials(username, password): 校验用户名和密码 返回: (success, role) 或 (False, None) conn get_db_connection() if not conn: return False, None try: cursor conn.cursor() sql SELECT password, role FROM t_user WHERE username%s AND status1 cursor.execute(sql, (username,)) row cursor.fetchone() if row and row[password] password: return True, row[role] # (True, admin) 或 (True, operator) return False, None except Exception as e: logger.error(f登录校验异常: {e}) return False, None finally: if conn: conn.close()这段代码有几个细节值得学。第一SQL 查询用的参数化写法不是字符串拼接能防 SQL 注入——这在课程设计的代码里属于加分项答辩时主动提这一点会显得你想过安全问题。第二查询条件带了 status1说明用户表里有一个逻辑删除/禁用字段被禁用的账号直接无法登录这个细节在文档里可以展开写。第三函数返回值是元组界面层拿到 (True, admin) 就知道接下来该往哪个主界面跳这个模式叫返回结果上下文比单纯返回 True 更有信息量。3.2 车辆进场登记parking_service 的车位分配策略车辆进场时界面会要求输入车牌号系统自动分配一个空车位并记录入库时间。这块的核心逻辑在 parking_service.py 的 enter_vehicle 方法里。我重点讲它的车位分配策略因为这是课设答辩的高频提问点。车位分配最简单的做法是顺序遍历找第一个空位但这份代码用的是先按区域分组、再在区域内找空位的策略def enter_vehicle(self, plate_no): 车辆进场: 分配车位并生成停车记录 plate_no: 车牌号如 京A12345 返回: (ok, message, park_record) # 1. 先检查车是否已在场内避免重复入场 exist self.get_parking_record_by_plate(plate_no, statusIN) if exist: return False, 该车辆已在场内, 请勿重复登记, None # 2. 查所有空车位优先从 A 区低编号开始分配 sql SELECT space_no, zone FROM t_parking_space WHERE status0 ORDER BY CASE zone WHEN A THEN 1 WHEN B THEN 2 ELSE 3 END, CAST(SUBSTRING(space_no, 2) AS UNSIGNED) LIMIT 1 # 执行查询后拿到目标车位更新车位状态为占用插入停车记录这个 ORDER BY 的技巧是一个亮点先把区域按 A、B、其他拍优先级然后使用 SUBSTRING 提取车位编号的数字部分做排序。这意味着分配停车场时遵循顺序原则车位不会出现随机跳动看起来非常稳——这在实际进场排队场景里很合理。代码里还加了重复车牌判断防止同一辆车在系统里被二次登记这个保护机制对于演示场景非常有价值如果上课演示时手滑输错车号又回车了至少不会产生脏数据。3.3 计费引擎fee_calculator 的按小时/按时段计费逻辑计费是这个系统的灵魂功能也是课设报告里最能写出深度的模块。fee_calculator.py 没有把费率写死在代码里而是每次结算时从数据库加载费率规则。这意味着临时改了费率设置后已经停着的车下次结算就按新规则走不需要重启系统。来看它的核心结算函数def calculate_fee(self, entry_time, exit_time, fee_typeHOUR): 计算停车费用 entry_time: 入场 datetime exit_time: 出场 datetime fee_type: HOUR 按小时 / DAY 按天封顶 返回: (amount, detail_desc) if exit_time entry_time: return 0, 时间无效, 请检查 minutes (exit_time - entry_time).total_seconds() / 60 hours minutes / 60 # 从数据库加载费率规则 fee_rules self.get_fee_rules() # [{hour_price, max_day_price, free_minutes}] # 免费时长判断 if minutes fee_rules[free_minutes]: return 0, 免费时长内 # 按小时向上取整计费 billable_hours math.ceil(hours) amount billable_hours * fee_rules[hour_price] # 当天封顶逻辑: 超过 8 小时按天计, 避免用户被一小时一小时堆出天价 max_day fee_rules[max_day_price] if amount max_day: return max_day, f已达单日封顶 {max_day} 元 return amount, f{billable_hours} 小时 x {fee_rules[hour_price]} 元/时逻辑顺序值得关注先算总分钟数、再查免费时长、然后小时数向上取整、最后与封顶价格比较。我认为这个计费模型最大的优点是对边界情况的处理——实际做课设时最常见的翻车场景是车辆停了 8.5 小时计算 9 小时费用后超出单日上限应该按封顶价结算。如果没有这一步比较用户的停车费可能高达实际费用的一倍答辩时被问费率是否合理就容易露出马脚。3.4 日志与数据回滚记录关键操作日志失败时能定位问题很多课设项目跑不起来、或者跑出错误结果时开发者和使用者都是一头雾水。这个项目的处理方式是在 core 层各模块中埋了 logger进出场、收费结算、删除记录这几个关键动作全部会写到 logs/system.log 里。我在拆这份代码的时候特意查看了日志模块的配置方式。它用的是 Python 标准库 logging设置了文件回滚RotatingFileHandler日志文件超过 1MB 会自动分割保留备份避免了长时间运行后日志文件膨胀。每一行日志都记录了操作时间和操作结果比如[2024-05-20 14:32:08] [INFO] 车辆 沪A88888 进场, 分配车位 A03, 操作员 operator1 [2024-05-20 16:12:55] [ERROR] 车辆 苏B12345 出场结算失败: 记录不存在这种日志格式对排查问题帮助很大。如果某辆车出场时报错看日志就能定位到是进场记录没有落库、还是结算时状态没更新。更重要的是这套日志机制可以直接在文档里写成系统具备操作审计能力如果你的课设要求里面有系统可靠性设计这一小节日志就是一个实实在在的料。4. 项目运行指南从零开始把系统跑起来4.1 环境准备Python 版本与依赖安装注意事项运行这个项目对 Python 版本没有特别苛刻的要求Python 3.8 及以上都可以推荐 3.10 或 3.11。主要原因是 Tkinter 在 Python 3.8 之后的标准库中已经非常稳定PyMySQL 的最新版本也对新版 Python 做了兼容。依赖安装就一条命令在项目根目录执行pip install -r requirements.txtrequirements.txt 里实际最核心的只有两项PyMySQL 用来连接 MySQL其他几个工具库要么是辅助。如果你在安装 PyMySQL 的时候遇到网络波动或者版本冲突我一般会先升级 pip 再装pip install --upgrade pip pip install PyMySQL1.1.0这里给你提个醒不要去 pip install pymysql 之外再装 MySQLdb两个库混用容易引发混乱。这个项目从连接建立到数据查询统一走 PyMySQL保持一条链路最省心。4.2 MySQL 初始化执行 SQL 脚本建库建表如果你本机还没有 MySQL 环境先装一个 MySQL 8.x 的社区版安装时记得把 root 密码记牢后面 config.py 里要用。建库建表有两种方式推荐直接用命令行导入脚本。打开终端进到项目 db 目录下mysql -u root -p parking.sql这个命令会一次性帮你做完这些事情创建 parking_system 数据库、创建 t_user、t_parking_space、t_parking_record、t_fee_rule 四张表、插入初始管理员账号和初始车位数据。执行完以后你可以验证一下SHOW TABLES; USE parking_system; SELECT * FROM t_user;如果你在 Windows 上没把 mysql 命令加进系统 PATH那就在 MySQL 客户端工具如 Navicat 或者 MySQL Workbench里面打开 parking.sql 文件直接执行效果一样。SQL 脚本里我建议你重点看两处一处是 t_parking_space 的 INSERT 语句看看预置了多少车位另一处是 t_fee_rule 的初始记录看看默认的每小时收费是多少——这两处数据决定你打开界面后看到的第一眼内容。注意如果执行脚本时报 ERROR 1046 (3D000) 之类的错误通常是因为脚本里缺少 CREATE DATABASE 语句或者你的 MySQL 账号没有建库权限。这份项目的脚本里已经带了 CREATE DATABASE IF NOT EXISTS所以大概率不会遇到但如果你的 MySQL 账号权限被收紧了在 root 账户下执行一次即可。4.3 启动与登录入口文件、初始账号和常见启动报错排查环境准备好以后启动就只是执行一个文件的问题python main.py如果你是在项目根目录下启动代码内部的相对路径都能正确找到 config.py。第一眼会弹出登录窗口输入脚本预置的账号 admin/admin123进入的是管理员主界面。启动阶段最常见的坑有三个。第一个坑报 ModuleNotFoundError: No module named pymysql说明依赖没装上回到第 4.1 步把依赖装齐。第二个坑报 pymysql.err.OperationalError: (1045, Access denied for user)这是 config.py 里的密码和你 MySQL 实际密码不一致去改配置文件的 DB_PASSWORD 字段。第三个坑点击登录后窗口卡住不动大概率是数据库连接超时检查 MySQL 服务是否启动、config.py 里的 DB_HOST 是不是写成了远程地址。4.4 功能演示流程走一遍注册→入场→出场→结算的全流程系统跑起来后建议你按这个顺序过一次全流程确认所有功能都正常。第一步先不进系统在登录窗口试一下注册账号现场注册一个普通操作员账号——这个功能对应的是 t_user 表的 INSERT 操作能走通就说明数据库连接和写入都正常。第二步使用 admin 登录进主控台先看车位状态的列表页此时应该能清晰看到哪些车位空闲、哪些占用。第三步录一辆车入场比如输入测A0001系统会自动分配空闲车位并在列表里刷新状态。第四步等两分钟再对这辆车做出场结算此时计费金额应该是 0因为免费时长还没过这是正常的——但如果想看真实计费可以把系统时间往前调或者直接改 t_fee_rule 表的 free_minutes 为 0重启系统再测。5. 避坑与常见问题排查我在拆这个项目时遇到的四个典型翻车点5.1 中文乱码Tkinter 界面和数据库之间的字符集对齐问题现象界面按钮和标签上的中文全部显示成方块或问号数据库里插入的车牌号变成乱码。原因MySQL 连接时没有指定 charset或者 MySQL 表默认字符集是 latin1Python 端传过来的 UTF-8 编码在入库时被错误转码。解决在 config.py 的数据库连接参数里显式加上 charsetutf8mb4注意这里写 utf8mb4不是 utf8因为 utf8 在 MySQL 里不是完整的 UTF-8emoji 类字符存不了。同时在建库语句里把 DEFAULT CHARSET 设为 utf8mb4。改完后重启系统重新执行 parking.sql乱码问题就消失了。5.2 端口号冲突3306 端口被占用导致数据库连不上现象main.py 能启动但点击登录按钮后报 10061 Cant connect to MySQL server。原因MySQL 服务没有启动或者端口被其他程序占用了。Windows 上最常见的是安装了多个 MySQL 版本旧版本的残留服务占着 3306。解决在命令行执行 netstat -ano | findstr :3306 看端口被哪个进程占用。如果确实是被 MySQL 占用确认你现在连的是不是这个实例如果是其他程序占用就在 MySQL 配置文件里换一个端口比如 3307然后把 config.py 里的 DB_PORT 改成 3307。血泪经验改完配置要同时改 SQL 脚本里的连接参数不然脚本建库连的还是一个端口。5.3 时间戳错乱计费金额出现负数或天价账单现象车辆出场结算时金额显示 -5 元或者停了 1 小时却算出 200 元。原因入场时间记录的是系统本地时间但 MySQL 的连接 time_zone 设置和 Python 端不一致导致 datetime 字段在读取时发生了时区偏移。解决在 config.py 的数据库连接参数中加入 init_commandSET time_zone 08:00强制统一时区。同时确认你操作系统的时区属于北京时间UTC8。这个坑在课程设计演示时尤其致命——你在台上演示停了一辆车结果账单是负数下面的老师就会觉得你系统不稳定。从那以后我每次搭 Python MySQL 项目都会首先把时区参数检查一遍再开始写业务代码。5.4 主键冲突重复执行 SQL 脚本导致初始数据脏乱现象执行了两次 parking.sql界面显示车位数量翻倍或者用户名重复。原因CREATE TABLE IF NOT EXISTS 只会建一次表但 INSERT 语句没有做幂等处理第二次执行脚本时把初始数据又插入了一遍。解决在 parking.sql 中的 INSERT 语句前加上条件判断或者在执行脚本前先手动清空表TRUNCATE TABLE t_user; TRUNCATE TABLE t_parking_space; 然后再重新导入。SQL 脚本里加入DELETE FROM t_user;之类的清空语句会更稳妥——这个教训来自我用初始化脚本时先后手插了两次车位数据导致页面上的 A01 到 A20 每个车位出现了两条记录整个列表瞬间变成 40 行。6. 二次开发思路从课程设计到完整系统的三层改造升级6.1 第一层改造把 Tkinter 界面和 core 层彻底解耦换成 Web API拿这份源码做课设可能够了但如果你想在项目里加一点区分度的亮点第一个建议是把 core 层服务改造成 REST API。具体做法是新建一个 api 层用 Flask 把 parking_service 和 fee_calculator 里的方法包成 HTTP 接口# api/parking_api.py from flask import Flask, request, jsonify from core.parking_service import ParkingService app Flask(__name__) service ParkingService() app.route(/vehicle/enter, methods[POST]) def vehicle_enter(): data request.get_json() ok, msg, record service.enter_vehicle(data[plate_no]) if ok: return jsonify({code: 0, message: msg, data: record}), 200 return jsonify({code: 1, message: msg}), 400改造完你会得到一套前后端分离的架构Tkinter 界面或者你顺手换个 Web 前端通过 HTTP 调用业务接口。这个设计在课设报告里可以作为系统扩展性设计来写段内容而且 API 化之后后续再加微信小程序端或手机 H5 端就简单了。6.2 第二层改造为计费引擎增加梯度价格和优惠券支持现在的计费规则是按小时单价乘时长再加一个当日封顶。如果想升级计费功能你可以在 fee_rule 表里增加字段第一时段单价、第二时段单价、时段切换时刻、优惠券抵扣金额。改造时只需要动 fee_calculator.py 中的 calculate_fee 函数核心模式是把它改成读取规则列表逐条匹配。我在自己就见过一个类似的项目改造是把计费逻辑改成了白天每小时 5 元、夜间 8 点后到次日 6 点每小时 2 元的两段式计费。改动量不大但演示效果提升明显答辩时你可以现场展示 18:50 入场的车和 19:10 入场的车最终费用不同。实现这个改造的关键点是在取费规则时多查一个 time_slot 字段然后根据入场时间落在哪个时段来选择费率。核心代码只需要加一个日期判断分支其他的沿用现有结构不变。6.3 第三层改造增加数据可视化和月度收益报表最后这层改造是为管理员端加一个统计报表模块。原项目的主窗口是 Treeview 表格展示车辆列表但缺少营收统计。你可以引入 matplotlib 画柱状图展示最近七天的日营收或者用饼图展示 A 区和 B 区的停车占用率。这个功能不用改动现有表结构直接基于 t_parking_record 表做聚合查询即可。聚合查询的 SQL 可以这样写SELECT DATE(exit_time) AS day, SUM(fee_amount) AS revenue FROM t_parking_record WHERE statusOUT AND exit_time DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY DATE(exit_time) ORDER BY day ASC;这层改造的价值是让你的项目从能记录和计费升级到能辅助管理人员做决策课设文档里的系统价值这一章瞬间有了具体素材。你在写文档时可以把改造前后的界面截图对照放进去导师看到的就不仅仅是你的工程实现能力还有你的数据驱动思维。6.4 验证和收尾每次改动后跑一遍回归测试清单每次改完代码建议按这个清单走一遍回归确保没有改崩原有功能管理员登录成功且有完整权限普通操作员没有报表菜单同一车牌连续两次入场会被拦截并提示错误免费时长内出场金额为 0超过免费时长后按规则正确计费当日封顶生效模拟停车 10 小时费用不超过 max_day_price重启系统后已入场车辆仍然在场内列表保留数据持久化验证这个验证清单表面上是做测试实际上是帮你在演示前建立信心。我自己的习惯是无论改了哪一处都要以最快速度把注册→登录→入场→出场→结算这个最短链路走一遍——因为课程设计答辩那天你不知道机器是不是换了一台MySQL 密码是不是变了环境变量是不是丢了提前确认最短链路能通心里就有底。希望这份拆解能帮你在做自己的版本时少踩几个坑直接把精力放在值得展示的地方。本文还有配套的精品资源点击获取