Python超市管理系统源码实战:Flask+SQLite收银库存全流程
简介这是一份面向Python初学者与课程设计学习者的超市管理系统源码包围绕员工管理、客户管理、登录验证与商品库存记录等日常运营场景展开适合用来练习GUI界面搭建、文件持久化存储与模块化组织方式。压缩包共13个文件约8KB以7个txt数据与配置文本、4个py功能模块、1个md说明文档和1个log日志文件为主其中py文件分别承担员工、顾客、登录窗口与登录验证等职责txt多用于保存账户、商品及顾客信息md提供项目说明log记录运行与警告信息。目前已有332人学习下载。通过阅读这套代码读者可以理解Tkinter界面设计、登录校验、异常处理与logging日志记录等关键环节并借鉴employee、customer等模块的拆分思路快速搭建自己的管理系统课程作业或练手项目。1. 从一份 Python 超市管理系统源码说起它到底能跑通哪些真实业务如果你正在找一份能直接跑起来、代码结构清晰、业务闭环完整的 Python 超市管理系统源码那这份资源大概率能省掉你从零搭架子的一周时间。它不是那种只写了增删改查的玩具 Demo而是把商品建档、库存预警、收银结算、会员折扣、销售流水、日结报表这几条主线都串了起来。技术栈是 Python Flask SQLite前端用 Jinja2 模板加少量原生 JS没有重型前端框架对新手友好对熟手也方便二次改造。适合谁一是课程设计或毕设需要完整业务链的同学二是想拿一个中小型 MIS 系统练手 Flask 分层设计的开发者三是小超市老板想低成本搞一套能用的收银后台。我拆过不少同类源码很多项目跑起来就报错这份的依赖和初始化脚本相对完整坑主要集中在数据库路径和编码上后面会细说。2. 环境搭建与数据库初始化把 SQLite 表结构一次建对2.1 依赖安装与项目结构速览拿到源码包后第一件事不是急着python app.py而是先看目录。常见结构是app.py作为入口models.py放 ORM 模型views/下按模块拆蓝图static/和templates/分别放静态资源和页面instance/或data/放 SQLite 文件。我一般会先建虚拟环境避免污染全局包。python -m venv venv # Windows 下激活 venv\Scripts\activate # macOS / Linux 下激活 source venv/bin/activate pip install flask flask-sqlalchemy flask-login # 如果源码里有 requirements.txt直接 pip install -r requirements.txt这里有个参数要留意flask-sqlalchemy的版本和 Flask 版本有绑定关系。Flask 2.3 以上配 SQLAlchemy 3.x 是稳的如果源码里写的是Flask1.1.2那 SQLAlchemy 得降到 2.4 附近否则Model.query会报AttributeError。我一般会先pip show flask确认版本再决定要不要改 requirements。2.2 建表与初始数据别让空库把你劝退SQLite 的好处是零配置坏处是路径写错就默默建到别处去了。源码里常见两种初始化方式一种是db.create_all()在应用启动时自动建表另一种是单独一个init_db.py脚本。我建议先跑初始化脚本把商品分类、默认管理员、几个测试商品塞进去不然登录进去一片空白你都不知道是代码坏了还是没数据。# init_db.py 典型写法 from app import app, db from models import User, Category, Product with app.app_context(): db.create_all() # 建表已存在则跳过 # 默认管理员密码记得改 if not User.query.filter_by(usernameadmin).first(): admin User(usernameadmin, passwordadmin123, roleadmin) db.session.add(admin) # 基础分类 for name in [饮料, 零食, 日用品]: if not Category.query.filter_by(namename).first(): db.session.add(Category(namename)) db.session.commit() print(初始化完成)逻辑说明with app.app_context()是 Flask 应用上下文没有它db对象拿不到配置。db.create_all()只建缺失的表不会改已有表结构所以如果你改了模型字段得删库重来或者手动ALTER TABLE。参数上password明文存储是这类源码的通病后面避坑章节会讲怎么换成哈希。初始数据里商品可以只放两三条够你验证收银流程就行。提示SQLite 文件默认在instance/目录下如果代码里写的是相对路径sqlite:///supermarket.db实际生成位置取决于启动时的工作目录。我习惯改成绝对路径省得找不到库。3. 核心业务模块拆解商品、库存、收银三条线怎么串3.1 商品管理与库存预警的实现逻辑商品模块看着简单但字段设计直接决定后面收银顺不顺。这份源码里Product模型一般包含barcode、name、price、cost、stock、category_id、alert_stock这几个字段。其中alert_stock是库存预警阈值收银扣减库存后如果stock alert_stock后台首页会标红提醒。这个设计比单纯记库存数要实用很多同类源码漏了这层。# models.py 片段 class Product(db.Model): id db.Column(db.Integer, primary_keyTrue) barcode db.Column(db.String(32), uniqueTrue, nullableFalse) name db.Column(db.String(64), nullableFalse) price db.Column(db.Float, nullableFalse) # 售价 cost db.Column(db.Float, default0.0) # 进价用于算毛利 stock db.Column(db.Integer, default0) alert_stock db.Column(db.Integer, default10) # 低于此值预警 category_id db.Column(db.Integer, db.ForeignKey(category.id))参数说明barcode加唯一索引扫码枪录入时不会重复建档。price和cost用 Float 在金额计算上会有浮点误差常见做法是改用Numeric(10, 2)或者存整数分但这份源码为了简单用了 Float你在做日结报表时可能会看到0.30000000000000004这种数心里有数就行。库存扣减我一般会放在收银事务里和订单写入同一个db.session.commit()避免卖了货库存没减。3.2 收银结算与会员折扣的代码路径收银是这套系统的核心。流程通常是扫码或输入条码 → 查商品 → 加入购物车前端 JS 维护→ 选会员 → 算折扣 → 提交订单 → 扣库存 → 写流水。会员折扣一般按等级来比如普通会员 1.0、银卡 0.95、金卡 0.9。这里有个容易翻车的地方折扣算完的金额要四舍五入到分不然日结对不上。# views/cashier.py 结算逻辑简化版 app.route(/checkout, methods[POST]) def checkout(): data request.get_json() items data.get(items, []) # [{product_id, qty}] member_id data.get(member_id) # 可为 None total 0.0 order_items [] for it in items: p Product.query.get(it[product_id]) if not p or p.stock it[qty]: return jsonify({code: 1, msg: f{p.name} 库存不足}) total p.price * it[qty] order_items.append((p, it[qty])) discount 1.0 if member_id: m Member.query.get(member_id) discount m.discount if m else 1.0 pay_amount round(total * discount, 2) # 关键保留两位 order Order(totaltotal, discountdiscount, pay_amountpay_amount, member_idmember_id) db.session.add(order) db.session.flush() # 拿到 order.id for p, qty in order_items: p.stock - qty db.session.add(OrderItem(order_idorder.id, product_idp.id, qtyqty, pricep.price)) db.session.commit() return jsonify({code: 0, pay_amount: pay_amount})逻辑说明db.session.flush()把订单写进事务但没提交目的是拿到自增order.id给明细用。round(total * discount, 2)是必须的否则前端显示和数据库存的可能差一分钱。库存检查放在循环里逐条判断比先查后扣要安全但高并发下仍有超卖风险小超市单机用没问题真要抗并发得上行锁或乐观锁。会员折扣从Member表读没会员就按原价这个分支要测到。3.3 销售流水与日结报表的查询写法流水表Order一般记id、total、pay_amount、member_id、created_at。日结报表就是按日期分组求和。SQLite 的日期函数和 MySQL 略有不同用func.date()比较稳。from sqlalchemy import func # 日结按天汇总营业额和单数 rows db.session.query( func.date(Order.created_at).label(day), func.count(Order.id).label(order_count), func.sum(Order.pay_amount).label(revenue) ).group_by(func.date(Order.created_at)).all() for r in rows: print(r.day, r.order_count, round(r.revenue, 2))参数说明func.date()在 SQLite 下把2024-06-01 12:30:00截成2024-06-01MySQL 下同样可用。func.sum返回的是 Decimal 或 Float打印前round一下。如果created_at字段没设默认值插入订单时得手动datetime.now()否则分组出来全是 NULL。我见过有人忘了这茬报表一片空白查了半天以为是 SQL 写错了。4. 避坑与排查这份源码最容易翻车的五个地方4.1 现象启动报No module named flask_sqlalchemy→ 原因虚拟环境没激活或装错解释器 → 解决确认which python指向 venv重装依赖这个坑新手命中率极高。你在终端pip install了但 IDE 里跑的时候用的还是系统 Python。解决就一句话在 IDE 里把解释器切到 venv 下的python.exe或bin/python。我一般会在项目根目录放一个.env或者直接看pip -V的路径对不对。4.2 现象登录后页面 500日志报sqlite3.OperationalError: no such table: user→ 原因没跑初始化脚本或数据库路径不一致 → 解决确认SQLALCHEMY_DATABASE_URI指向的库文件存在且已建表常见情况是app.py里配置的是sqlite:///supermarket.db而init_db.py里导入的 app 配置不同结果建到了另一个文件。统一做法是把数据库 URI 写进config.py两边都从同一个配置读。另外删库重来之前先备份别问我怎么知道的。4.3 现象收银提交后库存没减 → 原因扣库存代码在commit之后或异常被吞 → 解决把库存扣减和订单写入放同一事务检查try/except是否rollback有些源码为了“健壮”在结算外面包了try/except但 except 里只print不rollback结果订单写了一半库存没动。正确做法是except里db.session.rollback()再返回错误。你可以在扣库存后手动抛个异常测试看订单和库存是不是一起回滚。4.4 现象金额出现0.30000000000000004→ 原因Float 浮点精度 → 解决展示和存储时round(x, 2)或改用Numeric前面提过Float 做金额计算必然有精度问题。临时方案是所有输出前round彻底方案是把price、pay_amount改成db.Numeric(10, 2)。改字段类型后记得重建表SQLite 不支持直接改列类型。4.5 现象中文商品名存进去变乱码 → 原因SQLite 连接编码或文件编码不一致 → 解决确保 Python 文件 UTF-8连接串加?charsetutf8SQLite 本身默认 UTF-8乱码多半是源码文件用了 GBK 保存或者模板渲染时没声明charset。检查templates/base.html里有没有meta charsetUTF-8以及app.py开头有没有# -*- coding: utf-8 -*-。我一般统一用 UTF-8 无 BOM省心。5. 二次改造与验证把明文密码换掉再跑一遍全流程5.1 用 Werkzeug 做密码哈希别让 admin123 裸奔这份源码默认明文存密码拿来练手可以真要放到局域网用就得改。Flask 自带的werkzeug.security就够不用额外装包。from werkzeug.security import generate_password_hash, check_password_hash # 建用户时 admin User(usernameadmin, passwordgenerate_password_hash(admin123), roleadmin) # 登录校验时 user User.query.filter_by(usernameform.username).first() if user and check_password_hash(user.password, form.password): login_user(user)逻辑说明generate_password_hash默认用 pbkdf2每次生成的盐不同所以同一个密码存进去的值不一样这是正常的。check_password_hash负责比对。改完之后原来明文存的用户得手动重置密码或者写个一次性脚本批量哈希。参数上不用调默认强度够用。5.2 全流程验证清单从建档到日结走一遍改完代码别急着说“好了”按这个顺序跑一遍能挡住九成问题步骤操作预期结果1用 admin 登录进入后台首页库存预警区正常显示2新建商品条码填唯一值列表出现该商品库存为初始值3收银台扫码/输入条码加购两件购物车金额正确4选会员结算应付金额按折扣计算保留两位5回商品列表看库存库存已扣减低于阈值标红6查日结报表当天营业额和单数与实际一致7退出重登会话正常密码哈希校验通过这张表我每次改完收银逻辑都会走一遍尤其是第 4 和第 5 步事务没处理好这里必露馅。第 6 步如果数字对不上先看created_at是不是 UTC 时间SQLite 默认存 UTC你本地是东八区的话日期可能差一天报表按func.date分组就会错位。解决办法是在写入时用本地时间或者查询时做时区转换。5.3 一个我常留的后门用 pytest 写三条冒烟测试手动点页面费时间我一般会补三条最简测试改完代码跑一下比肉眼靠谱。# test_smoke.py import pytest from app import app, db from models import Product pytest.fixture def client(): app.config[TESTING] True app.config[SQLALCHEMY_DATABASE_URI] sqlite:///:memory: with app.app_context(): db.create_all() db.session.add(Product(barcode6901, name测试可乐, price3.0, stock100)) db.session.commit() yield app.test_client() def test_login_page(client): assert client.get(/login).status_code 200 def test_checkout_reduces_stock(client): resp client.post(/checkout, json{ items: [{product_id: 1, qty: 2}] }) assert resp.get_json()[code] 0 p Product.query.get(1) assert p.stock 98 def test_checkout_insufficient_stock(client): resp client.post(/checkout, json{ items: [{product_id: 1, qty: 999}] }) assert resp.get_json()[code] 1逻辑说明用内存库跑测试不碰真实数据。第一条测页面能开第二条测扣库存第三条测库存不足拦截。参数上TESTINGTrue让 Flask 把异常抛出来而不是吞掉方便定位。这三条过了基本功能就不会有大毛病。从那以后我每次改完收银相关代码都强制先跑一遍冒烟测试再手动点省得来回翻车。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

AI制图实测:10分钟生成架构图与流程图

AI制图实测:10分钟生成架构图与流程图

相信不少朋友都经历过这样的场景:刚画完一张系统架构图,产品经理又改了两版需求;刚理清一条业务主线,对接方又加了三个分支。画图这件事,听着很轻松,真正动手才发现,框要对齐、线要避开交叉、字…

2026/10/13 22:18:56 阅读更多 →
AI编程大模型免费活动的技术真相与工程实践指南

AI编程大模型免费活动的技术真相与工程实践指南

1. 项目概述:这不是“薅羊毛清单”,而是一份AI编程模型能力演进的实时观测日志“最新免费AI编程大模型活动汇总 2026年10月8日更新”——这个标题乍看像电商促销页,实则藏着当前AI工程落地最真实的脉搏。我从2023年起持续跟踪国内大模型在开发…

2026/10/13 22:18:56 阅读更多 →
PyTorch目标检测实战:小黄人检测从数据准备到模型训练全流程

PyTorch目标检测实战:小黄人检测从数据准备到模型训练全流程

最近用PyTorch做图像识别练习,选了个特别有画面感的入门任务——小黄人检测。目标检测这个名字听着有点唬人,但拆开其实就两件事:先把图片里的小黄人找出来,再用矩形框把它框住。上学那会儿做这类需求,第一反应是搞滑动…

2026/10/13 22:18:56 阅读更多 →

最新新闻

免费帝国插件内容流水线搭建:采集、伪原创、发布与推送全流程避坑指南

免费帝国插件内容流水线搭建:采集、伪原创、发布与推送全流程避坑指南

简介:这是一款面向站长与SEO从业者的帝国CMS配套插件,聚焦关键词采集、文章采集、伪原创改写、自动发布与搜索引擎推送等环节,帮助希望提升站点收录与排名、又缺乏持续内容产出精力的用户搭建半自动化的优化流程。资源以zip压缩包形式提供&am…

2026/10/13 23:17:20 阅读更多 →
DETR论文笔记与源码解析:端到端目标检测的Transformer实践

DETR论文笔记与源码解析:端到端目标检测的Transformer实践

1. 从标题拆解这个项目到底在讲什么1.1 标题里的三个关键词:论文笔记、源码、DETR看到“论文笔记源码 DETR:End-to-End Object Detection with Transformers”这个标题,我第一反应是:这是一份典型的“论文精读代码复现”组合型笔记。它面向的…

2026/10/13 23:17:20 阅读更多 →
语音FFT变换详解:分帧、加窗、频谱泄漏与Python实现

语音FFT变换详解:分帧、加窗、频谱泄漏与Python实现

拿到一段语音,最先做的往往不是“听”,而是把它丢进傅里叶变换里,看看这个声音到底由哪些频率成分构成。语音信号分析里的FFT变换过程,本质上就是回答一个很基础但又绕不开的问题:这段声音里,低频、中频、高…

2026/10/13 23:17:20 阅读更多 →
LTMU元更新器:让长期目标跟踪不再因更新策略而丢目标

LTMU元更新器:让长期目标跟踪不再因更新策略而丢目标

最近在整理长期目标跟踪相关的资料时,又把这篇文章翻出来重读了一遍。说实话,很多跟踪领域的论文看的是“怎么把特征提得更好”,但LTMU这篇不一样,它瞄准的是一个常被忽略却又致命的问题——跟踪器到底该什么时候更新。这个决定看…

2026/10/13 23:17:20 阅读更多 →
Docker入门与实战——容器实战思考

Docker入门与实战——容器实战思考

容器实战思考1、Docker为什么会成功2、研发人员该如何看待容器2.1、快速上手新技术2.2、容器化的代码仓库2.3、面向业务编程2.4、使用Docker Hub发布开源项目3、容器化开发模式3.1、操作流程3.2、场景示例3.3、注意事项3.4、容器与生产环境1、Docker为什么会成功 Docker实现所…

2026/10/13 23:17:20 阅读更多 →
前馈算法(Feedforward)完全指南:多层感知机与矩阵运算——《Nature of Code》第10章神经网络系列 10.12

前馈算法(Feedforward)完全指南:多层感知机与矩阵运算——《Nature of Code》第10章神经网络系列 10.12

教程文档示例工程 【免费下载链接】website-archive Archive of the Coding Train website (first version) 项目地址: https://gitcode.com/gh_mirrors/we/website-archive 点击查看 免费下载 本文以 Coding Train 网站存档中《Nature of Code》第 10 章 Neural N…

2026/10/13 23:16:20 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →