本篇博客将带你深入剖析一个基于 Python、WxPython 与 SQLite 的 租车管理系统 源码。通过分层解读数据库管理、对话框封装、各业务面板和主入口,我们不仅了解整体架构,还能掌握核心代码片段的实现细节与设计思路。
语言:Python 3.x
GUI 框架:WxPython(含 wx.adv
、flatnotebook
插件)
数据库:SQLite,本地文件 car_rental.db
目录结构:
car_rental/
├─ 代码.py # 主程序(含 UI 与 DBManager)
└─ car_rental.db # SQLite 数据库(首次运行时自动创建)
程序入口即为 代码.py
,其中定义了 DBManager
、多个 wx.Dialog
、wx.Panel
以及主窗口 MainFrame
。
DBManager
类负责与 SQLite 的所有交互,包括表初始化、字段迁移、CRUD 操作及统计接口。
def _init_tables(self):
c = self.conn.cursor()
c.execute("""
CREATE TABLE IF NOT EXISTS admin (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
role TEXT NOT NULL DEFAULT '管理员'
)""")
# customers、vehicles、rentals 同理
self.conn.commit()
这里一次性创建了 admin
、customers
、vehicles
、rentals
四张表,并设置了主外键约束与默认值。
当版本迭代需要新增字段时,_migrate_vehicles()
与 _migrate_rentals()
会检测当前表结构,动态执行 ALTER TABLE ADD COLUMN
,确保旧数据库兼容新代码。
cols = [r["name"] for r in cur.execute("PRAGMA table_info(vehicles)")]
if "status" not in cols:
cur.execute("ALTER TABLE vehicles ADD COLUMN status TEXT NOT NULL DEFAULT '可租'")
self.conn.commit()
管理员管理:get_users()
, add_user()
, update_user()
, delete_user()
客户管理:get_customers()
, add_customer()
, update_customer()
, delete_customer()
车辆管理:get_vehicles(fuel, transmission, price_range)
, add_vehicle(...)
, update_vehicle(...)
, delete_vehicle(vid)
租赁管理:
查询所有租单:
def get_rentals(self):
return self.conn.execute("""
SELECT r.id, c.name AS customer, v.plate||'/'||v.model AS vehicle,
a.username AS operator, r.start_date, r.end_date,
r.total_price, r.status
FROM rentals r
JOIN customers c ON r.customer_id=c.id
JOIN vehicles v ON r.vehicle_id=v.id
JOIN admin a ON r.operator_id=a.id
""").fetchall()
新增租单:自动计算天数与总价,并更新车辆状态为“已租”
sd_dt = datetime.strptime(sd, "%Y-%m-%d")
days = (ed_dt - sd_dt).days + 1
price = self.conn.execute("SELECT price FROM vehicles WHERE id=?", (vid,)).fetchone()[0]
total = days * price
归还操作:更新租单状态与车辆状态
提供首页仪表盘所需数据,如总车辆数、可租/已租数量、本日/本月租赁数、近三日到期提醒等:
def available_vehicles(self):
return self.conn.execute(
"SELECT COUNT(*) FROM vehicles WHERE status='可租'"
).fetchone()[0]
def upcoming_returns(self):
td = datetime.now().strftime("%Y-%m-%d")
fu = (datetime.now()+timedelta(days=3)).strftime("%Y-%m-%d")
return self.conn.execute("""
SELECT c.name AS customer, v.plate||'/'||v.model AS vehicle, r.end_date
FROM rentals r
JOIN customers c ON r.customer_id=c.id
JOIN vehicles v ON r.vehicle_id=v.id
WHERE r.status='租赁中' AND r.end_date BETWEEN ? AND ?
ORDER BY r.end_date
""", (td, fu)).fetchall()
为了避免在多个面板中重复编写表单逻辑,引入了两种对话框类。
用于生成最基础的“字段—文本框”对话框,适合客户、管理员等简单信息录入。
class FormDialog(wx.Dialog):
def __init__(self, parent, title, fields, init=None):
super().__init__(parent, title=title)
self.ctrls = {}
vs = wx.BoxSizer(wx.VERTICAL)
for f in fields:
vs.Add(wx.StaticText(self, label=f), 0, wx.ALL, 5)
tc = wx.TextCtrl(self, value=(init.get(f,"") if init else ""))
self.ctrls[f] = tc
vs.Add(tc, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
# 标准按钮
sdb = wx.StdDialogButtonSizer()
# … 添加 “确定” 与 “取消”
self.SetSizer(vs)
调用示例:
dlg = FormDialog(self, "添加客户", ["姓名", "电话", "邮箱"])
if dlg.ShowModal() == wx.ID_OK:
data = dlg.get() # 返回 {"姓名": "...", "电话": "...", ...}
在 FormDialog
基础上增添下拉框、日期控件与图片选择,专用于车辆信息录入/编辑。
class VehicleDialog(wx.Dialog):
def __init__(self, parent, title, init=None):
super().__init__(parent, title=title)
# Plate、Model 等文本框
# 下拉:fuel choices = ["全部","汽油","柴油","电"]
# 日期:avail_start = wx.adv.DatePickerCtrl(...)
# 图片:wx.FileDialog 选择后展示
统一提供 get()
方法,输出格式化的字段字典,进一步传递给 DBManager
。
借助 wx.lib.agw.flatnotebook.FlatNotebook
,系统分为五大选项卡:首页、车辆管理、客户管理、租赁管理、用户管理。
wx.StaticText
+ wx.BoxSizer
布局展示各统计接口返回的数字。wx.ListCtrl
列表展示未来三天到期的租单。wx.ComboBox
与 wx.TextCtrl
可按燃料、变速箱与价格区间筛选车辆列表。wx.ListCtrl
展示 plate
、model
、fuel
、transmission
、price
等字段。wx.Bitmap
渲染。Bind(wx.EVT_CONTEXT_MENU)
触发 VehicleDialog
或删除确认。核心刷新逻辑:
data = self.db.get_vehicles(fuel, transmission, price_range)
self.list_ctrl.DeleteAllItems()
for row in data:
idx = self.list_ctrl.InsertItem(self.list_ctrl.GetItemCount(), row["plate"])
# 依次 SetItemText 对其他列赋值
与车辆管理类似,但仅包含 name
、phone
、email
三列,无图片与复杂过滤,复用 FormDialog
完成添加/编辑。
wx.ListCtrl
展示历史租单,并可通过右键“一键归还”,恢复车辆状态。start_date
或 end_date
变更时,以 datetime.strptime
解析并计算日期差,再乘以单价显示。仅对管理员账户进行管理,字段包括 username
、role
、可修改密码,保证只有授权用户能操作系统。
MainFrame
继承自 wx.Frame
,使用 FlatNotebook
承载五个面板,并在启动时完成:
DBManager
,自动创建/迁移表结构。Panel
作为选项卡页添加到 FlatNotebook
。app.MainLoop()
。零运维:SQLite 单文件数据库免安装,即插即用。
自动迁移:新增字段无缝兼容老数据,保障迭代升级平滑。
通用组件:封装 FormDialog
与 VehicleDialog
,极大减少重复代码。
界面体验:FlatNotebook
选项卡结构直观,列表+右键菜单交互符合桌面应用习惯。
可扩展性: