MySQL+Python仓库管理系统:窗口可视化界面从零搭建与TaoToken配置实践
发布时间:2026/10/2 13:44:22来源:尧图网络
1. 从零跑通 MySQL Python 仓库管理系统窗口可视化界面到底怎么搭很多人第一次做仓库管理系统卡住的地方不是 Python 语法而是三件事数据库表结构怎么设计、Tkinter 窗口怎么和数据库联动、以及后面接入大模型能力时 API 请求地址怎么统一管理。这篇就围绕 MySQL Python 仓库管理系统 窗口可视化界面这条主线把入库、出库、库存查询三个核心模块从建库建表到界面跑通完整走一遍最后再把 API 请求的 Base URL 切到 TaoToken 统一通道做一次连通性验证。先说清楚这套系统是什么、能做什么、适合谁。它是一个本地运行的桌面程序用 Python 的 Tkinter 做窗口界面用 pymysql 连接本机 MySQL 数据库实现货物入库登记、出库扣减、库存清单查询和按货物编号精确查询。适合刚学完 Python 基础、想找一个能写进简历或课程设计的小项目练手的人也适合需要给小型仓库做一套轻量管理工具的开发者。整套代码不依赖 Web 框架不需要部署服务器装好 MySQL 和 Python 就能跑。我试过把这类系统直接堆在一个文件里结果改一个字段要翻几百行所以下面会按模块拆开讲同时给出可直接复制的建表 SQL 和连接配置。你跟着做半小时内能看到窗口弹出来。核心检索词先明确MySQL 建表、Python 连接 MySQL、Tkinter 窗口可视化、仓库管理系统入库出库查询、TaoToken Base URL 配置。这几个词贯穿全文后面每个章节都会落到具体操作上。环境准备清单Python 3.8 以上、MySQL 5.7 或 8.0、pymysql 库。安装 pymysql 只需要一条命令pip install pymysql如果你用的是 PyCharm直接在终端里执行这条命令即可或者在 Settings 里的 Project Interpreter 添加。MySQL 安装完成后记得启动服务Windows 下可以在服务管理器里确认 MySQL 服务处于运行状态。数据库连接参数是后面所有模块的基础先记住这四个host、port、user、password再加上 db 名称。默认端口 3306本地开发 host 写 localhost 或 127.0.0.1。密码是你安装 MySQL 时设置的不要照抄别人的。这一节先把整体结构讲清楚下一节进入 TaoToken 前置配置再往后是完整的建表和界面代码。2. TaoToken 前置配置统一 API 通道与 Base URL 设置为什么一个本地仓库管理系统要提 TaoToken因为当你给系统加智能补货建议、自然语言查询库存、或者用大模型生成入库单摘要时代码里会散落各种 API 请求地址和密钥。TaoToken 提供的是统一通道把 Base URL 收敛到一个地址密钥集中管理换模型时不用改业务代码。TaoToken 是什么、能做什么它是一个 API 统一接入通道兼容 OpenAI 风格的接口协议。你原本写https://api.openai.com/v1的地方改成 TaoToken 的地址请求格式不变。适合需要在多个模型之间切换、又不想每个项目都维护一套密钥的开发者。官网地址https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址https://taotoken.net/api注意 API 地址不带 UTM 参数直接写https://taotoken.net/api即可。这个地址就是后面配置里的 Base URL。前置准备分三步。第一步注册并登录控制台拿到 API Key。控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite第二步在 API Keys 页面创建密钥。入口https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite第三步确认你要用的模型 ID。可以在模型对话页面先试一下。入口https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite如果你打算长期做编码类项目或者要接 Agent 工作流可以看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite接入文档在这里https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite配置的核心就三件套Base URL、API Key、Model ID。Base URL 填https://taotoken.net/apiAPI Key 填你创建的那串Model ID 填你选定的模型名。这三样在后面的 Python 请求代码里会用到。注意API Key 不要硬编码在提交到 Git 的代码里建议用环境变量或单独的配置文件并且把配置文件加入 .gitignore。对于仓库管理系统典型的大模型调用场景是用户输入「查询编号 A001 的库存」程序把这句话发给模型模型返回结构化的货物编号再走数据库查询。这样你就不用写复杂的正则解析。Base URL 统一后换模型只改 Model ID 一个字段。这一节把前置配置讲完了下一节进入可复制的建表 SQL 和 Python 连接配置。3. 可复制配置建表 SQL、pymysql 连接与 Tkinter 界面代码这一节是全文技术核心给出可直接复制的数据库建表语句、Python 连接配置和窗口界面代码。先建库建表。打开 MySQL 命令行或 Navicat执行以下 SQLCREATE DATABASE IF NOT EXISTS warehouse_db DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; USE warehouse_db; CREATE TABLE IF NOT EXISTS inbound ( inbound_no VARCHAR(32) NOT NULL COMMENT 入库单号, goods_code VARCHAR(32) NOT NULL COMMENT 货物编号, goods_name VARCHAR(64) NOT NULL COMMENT 货物名称, quantity INT NOT NULL DEFAULT 0 COMMENT 入库量, supplier_no VARCHAR(32) NOT NULL COMMENT 供应商编号, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (inbound_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT入库表; CREATE TABLE IF NOT EXISTS outbound ( outbound_no VARCHAR(32) NOT NULL COMMENT 出库单号, goods_code VARCHAR(32) NOT NULL COMMENT 货物编号, quantity INT NOT NULL DEFAULT 0 COMMENT 出库量, goods_name VARCHAR(64) NOT NULL COMMENT 出库货物, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (outbound_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT出库表; CREATE TABLE IF NOT EXISTS stock ( goods_code VARCHAR(32) NOT NULL COMMENT 货物编号, goods_name VARCHAR(64) NOT NULL COMMENT 货物名称, quantity INT NOT NULL DEFAULT 0 COMMENT 库存数量, supplier_no VARCHAR(32) NOT NULL COMMENT 供应商编号, PRIMARY KEY (goods_code) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT库存表;这里我把原代码里的中文表名改成了英文原因是中文表名在不同 MySQL 版本和字符集下容易出问题英文表名更稳。字段也做了规范化加了 created_at 时间戳方便后面做统计。接下来是数据库连接配置。建议单独放一个 db_config.py# db_config.py import pymysql DB_CONFIG { host: localhost, port: 3306, user: root, password: 你的MySQL密码, db: warehouse_db, charset: utf8mb4, cursorclass: pymysql.cursors.DictCursor, } def get_connection(): return pymysql.connect(**DB_CONFIG)用 DictCursor 的好处是查询结果直接是字典取字段用 row[goods_code]比下标 row[0] 可读性强得多。然后是主界面代码用 Tkinter 实现# main.py import tkinter as tk from tkinter import ttk, messagebox import pymysql from db_config import get_connection class WarehouseApp: def __init__(self): self.root tk.Tk() self.root.title(仓库管理系统) self.root.geometry(700x6007050) self.build_home() def build_home(self): for w in self.root.winfo_children(): w.destroy() tk.Label(self.root, text仓库管理系统, font(楷体, 30)).pack(pady40) tk.Button(self.root, text入库操作, font(楷体, 16), width20, height2, commandself.page_inbound).pack(pady10) tk.Button(self.root, text出库操作, font(楷体, 16), width20, height2, commandself.page_outbound).pack(pady10) tk.Button(self.root, text库存查询, font(楷体, 16), width20, height2, commandself.page_query).pack(pady10) tk.Button(self.root, text退出系统, font(楷体, 16), width20, height2, commandself.root.destroy).pack(pady10) def page_inbound(self): win tk.Toplevel(self.root) win.title(入库操作) win.geometry(500x500) fields [入库单号, 货物编号, 货物名称, 入库量, 供应商编号] entries {} for f in fields: tk.Label(win, textf, font(楷体, 14)).pack(pady6) e tk.Entry(win, font(楷体, 14)) e.pack() entries[f] e def submit(): vals {k: v.get().strip() for k, v in entries.items()} if not all(vals.values()): messagebox.showinfo(提示, 请填写完整信息) return conn get_connection() try: with conn.cursor() as cur: cur.execute( INSERT INTO inbound(inbound_no, goods_code, goods_name, quantity, supplier_no) VALUES (%s, %s, %s, %s, %s), (vals[入库单号], vals[货物编号], vals[货物名称], int(vals[入库量]), vals[供应商编号])) cur.execute( INSERT INTO stock(goods_code, goods_name, quantity, supplier_no) VALUES (%s, %s, %s, %s) ON DUPLICATE KEY UPDATE quantity quantity %s, (vals[货物编号], vals[货物名称], int(vals[入库量]), vals[供应商编号], int(vals[入库量]))) conn.commit() messagebox.showinfo(提示, 入库成功) except Exception as e: conn.rollback() messagebox.showerror(错误, str(e)) finally: conn.close() tk.Button(win, text确定, width20, commandsubmit).pack(pady20) def page_outbound(self): win tk.Toplevel(self.root) win.title(出库操作) win.geometry(500x400) fields [出库单号, 货物编号, 出库量, 出库货物] entries {} for f in fields: tk.Label(win, textf, font(楷体, 14)).pack(pady6) e tk.Entry(win, font(楷体, 14)) e.pack() entries[f] e def submit(): vals {k: v.get().strip() for k, v in entries.items()} if not all(vals.values()): messagebox.showinfo(提示, 请填写完整信息) return conn get_connection() try: with conn.cursor() as cur: cur.execute(SELECT quantity FROM stock WHERE goods_code %s, (vals[货物编号],)) row cur.fetchone() if not row or row[quantity] int(vals[出库量]): messagebox.showwarning(警告, 库存不足) return cur.execute( INSERT INTO outbound(outbound_no, goods_code, quantity, goods_name) VALUES (%s, %s, %s, %s), (vals[出库单号], vals[货物编号], int(vals[出库量]), vals[出库货物])) cur.execute( UPDATE stock SET quantity quantity - %s WHERE goods_code %s, (int(vals[出库量]), vals[货物编号])) conn.commit() messagebox.showinfo(提示, 出库成功) except Exception as e: conn.rollback() messagebox.showerror(错误, str(e)) finally: conn.close() tk.Button(win, text确定, width20, commandsubmit).pack(pady20) def page_query(self): win tk.Toplevel(self.root) win.title(库存查询) win.geometry(700x500) tk.Label(win, text货物编号, font(楷体, 14)).pack(pady10) code_entry tk.Entry(win, font(楷体, 14)) code_entry.pack() result_frame tk.Frame(win) result_frame.pack(fillboth, expandTrue, pady10) def query(): for w in result_frame.winfo_children(): w.destroy() code code_entry.get().strip() conn get_connection() try: with conn.cursor() as cur: if code: cur.execute(SELECT * FROM stock WHERE goods_code %s, (code,)) else: cur.execute(SELECT * FROM stock) rows cur.fetchall() if not rows: tk.Label(result_frame, text无记录, font(楷体, 14)).pack() return for r in rows: text f编号:{r[goods_code]} 名称:{r[goods_name]} 数量:{r[quantity]} 供应商:{r[supplier_no]} tk.Label(result_frame, texttext, font(楷体, 13)).pack(anchorw, pady3) finally: conn.close() tk.Button(win, text查询, width20, commandquery).pack(pady10) def run(self): self.root.mainloop() if __name__ __main__: WarehouseApp().run()这段代码相比原始版本做了几个关键改进用参数化查询%s替代字符串拼接避免 SQL 注入入库时同步更新 stock 表保证库存实时准确出库前先校验库存不足时拦截用 Toplevel 替代销毁主窗口再重建界面切换更流畅。如果你要给系统加 AI 能力比如自然语言查询可以在 page_query 里加一个输入框把用户的话发给 TaoToken 通道拿到货物编号后再查库。请求代码片段import requests import os TAOTOKEN_BASE_URL https://taotoken.net/api API_KEY os.getenv(TAOTOKEN_API_KEY) MODEL_ID 你选定的模型ID def parse_query(user_text): resp requests.post( f{TAOTOKEN_BASE_URL}/v1/chat/completions, headers{Authorization: fBearer {API_KEY}, Content-Type: application/json}, json{model: MODEL_ID, messages: [{role: user, content: f从这句话提取货物编号只返回编号{user_text}}]}, timeout30) return resp.json()[choices][0][message][content].strip()三件套在这里体现得很清楚Base URL 是https://taotoken.net/apiAPI Key 从环境变量读Model ID 单独配置。换模型只改 MODEL_ID。4. 验证请求与成功结果连通性测试与界面运行配置写完必须验证否则你不知道是数据库没连上还是 API 地址写错了。分两步验证。第一步验证 MySQL 连接。单独跑一段测试脚本from db_config import get_connection try: conn get_connection() with conn.cursor() as cur: cur.execute(SELECT VERSION()) print(MySQL 版本:, cur.fetchone()) conn.close() print(数据库连接成功) except Exception as e: print(数据库连接失败:, e)预期输出类似MySQL 版本: {VERSION(): 8.0.33} 数据库连接成功如果报Access denied for user rootlocalhost说明密码错了报Unknown database warehouse_db说明建库 SQL 没执行。第二步验证 TaoToken 通道连通性。用 curl 或 Python 都行Python 更贴近实际import requests, os resp requests.post( https://taotoken.net/api/v1/chat/completions, headers{Authorization: fBearer {os.getenv(TAOTOKEN_API_KEY)}, Content-Type: application/json}, json{model: 你选定的模型ID, messages: [{role: user, content: 回复连通成功}]}, timeout30) print(resp.status_code) print(resp.json())预期返回 HTTP 200body 里 choices[0].message.content 有内容。如果返回 401是 Key 问题返回 404检查 Base URL 是否多了或少了/v1。第三步运行主程序python main.py窗口弹出后点「入库操作」填入单号 IN001、货物编号 A001、名称 螺丝刀、入库量 100、供应商 S01点确定弹出「入库成功」。再点「库存查询」编号留空直接查能看到 A001 的记录数量 100。然后点「出库操作」填 OUT001、A001、出库量 30、出库货物 螺丝刀确定后提示「出库成功」。再查库存A001 数量变成 70。这一套流程走通说明数据库读写和界面联动都正常。成功结果的特征入库后 stock 表数量增加出库后减少查询界面实时反映。如果入库成功但查询看不到多半是入库时没同步更新 stock 表检查 ON DUPLICATE KEY UPDATE 那段。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一节对照真实报错逐个排查。这些错误在接入 API 和数据库时高频出现。报错一401 Unauthorized。返回体通常是{error: {message: Invalid API key}}。原因有三种Key 复制时带了空格、Key 已过期或被删除、请求头格式不对。检查Authorization: Bearer xxx中间是一个空格Key 前后无空白。去 API Keys 页面重新生成一个入口https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite报错二local proxy failed。这个报错说明请求发出时经过了本地代理设置但代理不可用。解决方式是检查系统环境变量 HTTP_PROXY / HTTPS_PROXY如果不需要代理就清空。在 Python 里可以显式禁用import os os.environ.pop(HTTP_PROXY, None) os.environ.pop(HTTPS_PROXY, None)或者在 requests 里传proxies{http: None, https: None}。注意不要配置任何非法的网络访问方式直连即可。报错三reading choices。典型报错KeyError: choices或TypeError: NoneType object is not subscriptable。原因是 resp.json() 里没有 choices 字段通常是请求失败返回了错误结构但代码直接取 choices。修复方式是先判断状态码data resp.json() if resp.status_code ! 200: print(请求失败:, data) else: print(data[choices][0][message][content])报错四OAuth 相关错误。如果你用的是 Claude Code 或 Codex 这类工具可能遇到 OAuth token 过期。这类工具通常有独立的认证流程检查配置文件里的 token 是否有效。对于 Codex配置文件在~/.codex/auth.json里面包含 Base URL、Key、Model ID 三件套确认 Base URL 指向https://taotoken.net/apiKey 是有效的Model ID 拼写正确。报错五pymysql 连接超时。报Cant connect to MySQL server on localhost。检查 MySQL 服务是否启动端口是否被占用防火墙是否拦截。Windows 下net start mysql启动服务。报错六中文乱码。界面显示问号或乱码。检查建库时字符集是否 utf8mb4连接配置里 charset 是否 utf8mb4Python 文件编码是否 UTF-8。报错七Tkinter 界面卡死。数据库查询在 UI 线程执行数据量大时界面无响应。解决方式是把查询放到子线程用root.after回传结果。小数据量可以忽略。报错八ModuleNotFoundError: No module named pymysql。没装库或装到了别的 Python 环境。确认 PyCharm 的解释器和你 pip 安装的是同一个用pip show pymysql查看安装位置。排查顺序建议先确认数据库能连再确认 API 能通最后跑界面。这样出问题时能快速定位是数据层还是网络层。6. 语义一致 CTA把系统跑起来之后继续扩展系统跑通后你可以继续加功能。比如加一个「智能补货建议」按钮把当前库存数据发给模型让它给出补货清单。或者加「自然语言查询」用户说「查一下螺丝刀还有多少」程序解析后查库。这些都需要稳定的 API 通道。模型对话调试入口https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewriteAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite长期编码或 Agent 工作流https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteClaude Code 接入参考https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude-code-anthropicutm_campaignrewrite最后给一个实用技巧把数据库连接配置和 API 配置都放到环境变量或单独的 config 文件代码里只引用变量名。这样换机器、换密钥、换模型都不用改业务逻辑。仓库管理系统这类小项目结构清晰比功能多更重要先把入库出库查询三条链路跑稳再往上叠 AI 能力出问题也容易定位。
网站建设高端定制企业官网