新闻详情

新闻详情

首页 / 资讯中心 / 详情

Flask+Django双框架构建农产品商城:从购物流程到数据可视化大屏

发布时间:2026/9/17 16:37:08来源:尧图网络
Flask+Django双框架构建农产品商城:从购物流程到数据可视化大屏
做农产品在线商城这类管理系统我看过太多半成品功能停留在增删改查数据分析就是统计一下订单总数页面打开像后台管理系统而不是面向消费者的商城。这次分享的项目是一个实际可用、能跑通完整购物链路还给经营者看数据的系统前半部分用 Flask 承载农产品超市商城的用户端、商品展示、购物车和下单结算后半部分用 Django 承载运营后台与数据可视化分析模块两者连同一个 MySQL 库大屏端用 ECharts 呈现。这套方案适合做课程设计、毕业设计也适合给中小型生鲜超市做轻量数字化改造下面我会把设计过程、核心代码、部署要点和踩过的坑一起写清楚。1. 系统整体设计与技术选型为什么一套系统同时用 Flask 和 Django1.1 每个框架都有自己的舒适区先说结论如果只做一个标准商城Django 一个框架就能扛下来如果只是给小程序提供接口Flask 也完全够用。但这套项目选择两者共存是因为它本质上是两套服务面向消费者的购物前端和面向运营管理者的后台分析端两边对框架的需求完全相反。购物前端要求路由灵活、接口轻量、响应快。这部分我选了 Flask它的路由和视图函数写起来非常直白一个商品列表接口、一个购物车操作接口几十行代码就能完成不会被自带的重型中间件干扰。电商场景里有大量边边角角的业务逻辑比如库存扣减前的校验、优惠价计算、购物车合并Flask 的自由度更高你不需要为这些细节去迁就框架的默认约定写起来很顺手。运营后台则要求规范、严谨最好开箱即用。这部分我用 Django它自带的 Admin 后台、ORM、迁移体系非常适合做运营数据录入、订单审核、用户管理。农产品的品类、产地、上下架状态这些字段经常要调整Django Admin 几乎不用额外写页面就能完成 80% 的管理工作。数据可视化大屏需要多维度聚合数据库记录Django 的 ORM 配合 TruncDate、Sum、Count 这类函数写聚合查询效率和可读性都很好。两边各有各的舒适区组合使用反而是务实的选择。1.2 Flask 与 Django 如何分工与通信整个系统拆成三个子服务Flask 商城服务监听 5000 端口负责前台商品展示、注册登录、购物车和订单结算Django 管理分析服务监听 8000 端口负责后台运营和数据大屏的聚合接口两者共用同一个 MySQL 数据库。这里有一个很多初学者容易踩的坑习惯性地为每个服务单独建库结果联调时数据对不上号。正确做法是共用一个业务库Flask 通过 SQLAlchemy 访问Django 通过自己的 ORM 访问表名、字段名保持严格一致。表结构由 Django 的 makemigrations 和 migrate 完成Flask 端只做读写不做结构变更这样权限清晰也避免误操作搞乱表结构。前端页面通过 AJAX 请求分别访问两个服务的接口大屏的全部数据来自 Django 提供的 JSON API。正式部署时我在前面加一层 Nginx 做反向代理把 /shop 路径转发到 Flask把 /admin 和 /api 路径转发到 Django。这样架构看起来比单一框架重一点但好处也实在Flask 服务万一挂了运营后台依然能查到所有订单Django 端要临时加报表接口也不影响线上交易。2. 数据库建模与核心模块设计先把农产品的特殊性放进表里2.1 表结构不是通用商城模板而是围绕农产品做的字段设计农产品商城和普通商品商城最大的差异在商品字段上。通用商城的商品表通常是 name、price、stock、description 就完了但农产品必须额外记录产地、单位、保鲜期、是否当季。比如五常大米要标产地黑龙江砂糖橘要标广西卖计量单位是斤而不是件成熟期和保鲜期直接影响能不能上架销售。这些字段不是锦上添花它们直接影响用户的购买决策也影响运营端判断库存周转。我实际建的几张核心表大致如下用户表 userid、username、password_hash、phone、address、create_time分类表 categoryid、name、parent_id蔬菜、水果、粮油、肉禽蛋奶做一级分类再细分二级商品表 productid、category_id、name、origin、unit、price、stock、sales_count、is_on_sale、cover_image、description、season_tag、shelf_life_days、create_time、update_time购物车表 cartid、user_id、product_id、quantity、checked、create_time订单表 ordersid、order_no、user_id、total_amount、status、receiver_name、receiver_phone、receiver_address、create_time、pay_time订单明细表 order_itemid、order_id、product_id、product_name、product_price、quantity、subtotal访问日志表 access_logid、user_id、product_id、access_time、access_type这张 access_log 表是很多商城项目容易忽略的但对数据可视化来说它特别关键。用户浏览了哪些商品、搜索了什么关键词、加购了什么品类这些行为数据是后面做转化漏斗和用户画像的依据。我的建议是哪怕现阶段不做用户行为分析也要先埋好这张表以后要扩展分析功能就不用大改表结构了。2.2 订单状态机、金额精度和索引优化订单状态我设计成整数状态码0 待支付、1 已支付待发货、2 已发货、3 已完成、4 已取消、5 已退款。这里我踩过一个很深的坑早期为了图方便直接在订单表里存待支付已发货这种中文文案结果前端展示要中文、接口返回要英文字段、统计分析要数字分组到处都要做判断改起来极其痛苦。改成整数状态码之后展示层用映射表解决统计层直接用数字分组舒服太多。金额字段一定要用 Decimal(10,2)绝对不要用 Float。这个坑是财务型项目的老生常谈但真的很多人踩。Float 的二进制浮点误差在商品金额计算里会悄悄累积出 0.001 的偏差尤其在多商品合计、优惠分摊这类场景下更容易暴露。Django 端用 DecimalFieldFlask 端 SQLAlchemy 用 Numeric(10,2)所有价格计算都在后端完成前端只做展示。索引方面订单表和访问日志表会随着业务快速膨胀。我在 order_item 的 order_id、product_id 上建了组合索引在 access_log 的 user_id、product_id、access_time 上建了组合索引这样大屏查询和订单详情查询都能走索引。另外分析类查询尽量避免 SELECT *Django 里用 .values() 控制返回字段Flask 里用 load_only()这些细节能明显缓解大屏加载时的数据库压力。3. 后端核心接口与购物流程实现从商品浏览到订单生成3.1 Flask 用户端核心接口以 Flask 商城服务为例最核心的链路是注册登录、浏览商品、加入购物车、提交订单、模拟支付、查看订单。这里先看商品列表和加购两个接口的写法。# app.py 核心路由片段 from flask import Blueprint, request, session, jsonify from models import db, Product, Cart from flask_sqlalchemy import BaseQuery shop_bp Blueprint(shop, __name__) # 商品列表支持分类过滤和关键词搜索 shop_bp.route(/api/products) def product_list(): category_id request.args.get(category_id, typeint) keyword request.args.get(keyword, ) page request.args.get(page, 1, typeint) per_page 12 query Product.query.filter(Product.is_on_sale True) if category_id: query query.filter(Product.category_id category_id) if keyword: query query.filter(Product.name.like(f%{keyword}%)) pagination query.order_by(Product.id.desc()).paginate( pagepage, per_pageper_page, error_outFalse ) items [{ id: p.id, name: p.name, price: str(p.price), origin: p.origin, unit: p.unit, cover_image: p.cover_image, stock: p.stock, sales_count: p.sales_count } for p in pagination.items] return jsonify({code: 0, data: items, total: pagination.total}) # 加入购物车先做登录校验和库存判断 shop_bp.route(/api/cart/add, methods[POST]) def add_cart(): if user_id not in session: return jsonify({code: 401, msg: 未登录}) data request.get_json() product Product.query.get(data.get(product_id)) if not product or not product.is_on_sale: return jsonify({code: 400, msg: 商品不存在或已下架}) if data.get(quantity, 0) 0: return jsonify({code: 400, msg: 数量不合法}) cart_item Cart.query.filter_by( user_idsession[user_id], product_idproduct.id ).first() if cart_item: cart_item.quantity data[quantity] else: cart_item Cart( user_idsession[user_id], product_idproduct.id, quantitydata[quantity] ) db.session.add(cart_item) db.session.commit() return jsonify({code: 0, msg: 加入成功})分页我用了 Flask-SQLAlchemy 内置的 paginate返回 total 数值给前端做分页组件没有把总页数、当前页这些也塞进 JSON因为前端可以从 total 和 per_page 算出来接口字段越少越好维护。3.2 Django 管理后台与销售数据接口的高效姿势Django 端承担两大任务一是运营人员日常管理二给数据可视化大屏提供聚合分析接口。运营后台的使用非常简单model 定义好后注册到 admin.py 就行。真正要花心思的是数据分析 API。我举个例子统计近 30 天每日销售额、TOP 商品、分类占比这是大屏上最常用的三个分析Django ORM 写起来非常优雅# dashboard/views.py from django.db.models import Sum, Count from django.db.models.functions import TruncDate from django.http import JsonResponse from django.utils import timezone from datetime import timedelta from shop.models import Order, OrderItem def daily_sales_trend(request): start_date timezone.now().date() - timedelta(days30) rows ( Order.objects .filter(status__in[1, 2, 3], pay_time__date__gtestart_date) .annotate(dayTruncDate(pay_time)) .values(day) .annotate( total_amountSum(total_amount), order_countCount(id) ) .order_by(day) ) return JsonResponse({code: 0, data: list(rows)}) def top_products(request): rows ( OrderItem.objects .values(product_name) .annotate(total_salesSum(subtotal), total_countSum(quantity)) .order_by(-total_count)[:10] ) return JsonResponse({code: 0, data: list(rows)})这套聚合写法在数据量不大的时候性能很好代码也直观。等以后订单量真的大了再考虑把聚合结果缓存到 Redis 或者提前在每日定时任务里生成汇总表。3.3 库存扣减和防重复提交的实际处理购物流程里最隐蔽的两个坑一个是库存超卖一个是订单重复提交。库存超卖的场景是这样的用户 A 和用户 B 同时看到最后一件商品同时点击购买如果代码里先查库存、判断 stock 0、再扣库存两个请求都可能通过校验导致库存变成 -1。解决办法是让扣减和条件判断在同一条 SQL 里完成# 安全扣减库存的伪代码core 是 DB 原生更新 updated Product.query.filter( Product.id product_id, Product.stock quantity ).update({ stock: Product.stock - quantity, sales_count: Product.sales_count quantity }) db.session.commit() if updated 0: # 说明库存不足或商品已变化回滚订单流程 raise RuntimeError(库存不足)关键点是 update 语句的 WHERE 条件里带上 stock quantity数据库层面的原子更新保证并发安全。这个办法对中小型商城完全够用不需要引入分布式锁。订单防重复提交这边我采用的方案是前端提交订单时加一个 pending 状态短时间内同一用户不能重复提交相同商品组合的订单后端在创建订单前检查该用户最近 10 秒内是否存在同商品的待支付订单有则直接返回原订单号。这个小保护能避免用户手滑双击或前端重试导致的脏数据。4. 数据可视化分析系统搭建大屏不是拼图表是回答问题4.1 先想清楚大屏给谁看、回答什么问题做数据可视化大屏之前先别急着选图表库应该先想清楚这张大屏给谁看看什么在这个项目里大屏主要给店长和运营者看核心问题只有三个卖得怎么样、什么卖得好、价格分布如何。围绕这三个问题我确定了六个图表近 30 天销售额与订单量趋势图折线图双 Y 轴各一级分类销售额占比环形图商品销量 TOP10横向柱状图农产品价格区间分布柱状图不同产地商品销量与库存对比双向柱状图用户访问热点商品排行排行列表六个图表覆盖经营分析最常见的场景。这里最需要注意的是数据口径统一销售额按已支付且未取消的订单统计销量按订单明细中的实际购买数量统计所有统计都在后端完成前端 ECharts 只负责渲染。项目前期因为前端自己算了部分指标出现过两次数字对不上的情况排查半天最后统一口径才解决。4.2 ECharts 大屏的数据接入实现大屏页面放在 Django 的 templates 里通过 AJAX 请求四个聚合接口/api/dashboard/summary、/api/dashboard/trend、/api/dashboard/category、/api/dashboard/top_products。前端拿到 JSON 之后做映射折线图的 xAxis 是日期、series 是销售额柱状图的 xAxis 是商品名、series 是销量。数据结构和图表配置解耦以后要换图表形态只需要改前端配置不用动后端。刷新策略我用的方案是 setInterval 每 30 秒拉一次 summary 轻量接口全量大屏数据每 5 分钟刷新一次。对单店规模完全够用没必要为了实时去引入 WebSocket成本和复杂度不成比例。这里分享一个踩过的细节坑Django 的 JsonResponse 返回中文 key 时模板里直接使用没问题但如果以后要把接口复用到小程序或 App建议后端统一返回 snake_case 的英文字段前端再做映射。我在项目里为了省事直接返回了中文名后面想复用接口做移动端适配时就多花了不少功夫。4.3 数据可视化大屏的快速搭建模板思路现在很多人一提到数据可视化大屏就想到 Power BI、FineReport 这些商业软件其实如果前端有一点基础用 ECharts 自己拼大屏是既灵活又省钱的方式。我的版式是 1920x1080 固定尺寸顶部标题栏中间主区域放趋势图左右两侧各放两个图表底部放商品排行。布局用 CSS Grid 完成背景用深色渐变加轻量发光边框动画尽量少否则低配电脑打开会卡。如果时间紧还能用 ECharts 社区模板快速起步但我会把静态数据和接口数据彻底分离先用 mock 数据把布局和样式调好再接后端接口。这样避免前段联调时反复刷新页面调试样式。5. 部署上线与常见问题速查从开发机到服务器的一次完整记录5.1 Linux 服务器部署流程与实际参数部署我用了一台 2核4G 的 Linux 服务器完整流程分四步第一步安装 MySQL、Nginx、Python 3.10创建虚拟环境装满 requirements.txt 里的依赖。Flask 端的依赖很轻Django 端需要把 mysqlclient 或 pymysql 装好还要装 pytz 处理时区。第二步Flask 端用 waitress 作为 WSGI 服务器监听 127.0.0.1:5000Django 端用 waitress 监听 127.0.0.1:8000。之所以两个都用 waitress是因为它在 Windows 和 Linux 下都能直接跑本地开发用 Windows部署到 Linux 环境完全一致。用 gunicorn 的话Windows 本地调试会有困难。第三步Nginx 配置反向代理。下面是一个精简但能用的配置示例server { listen 80; server_name your_domain_or_ip; location /shop/ { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /admin/ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /api/ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /media/ { alias /path/to/project/media/; } location /static/ { alias /path/to/project/static/; } }第四步用 systemd 管理两个服务进程设置开机自启MySQL 配置每日凌晨自动备份。备份用 mysqldump 加上 crontab 就能完成备份文件保留最近 7 天。5.2 高频问题速查表这里是项目上线后被问到最多的几个问题我整理成了速查表现象可能原因解决办法商品图片加载不出来图片保存路径和静态目录配置不一致统一让 Nginx 处理 /media确认目录权限可读购物车偶尔丢数据Flask session 默认存在 cookie容量有限使用 Flask-Session 把 session 存到 Redis 服务端大屏接口响应很慢聚合查询没走索引或者结果集过大检查表索引给热点接口加 Redis 缓存Django 后台不能上传图片MEDIA_URL / MEDIA_ROOT 配置错误检查 settings.py 的 MEDIA 配置重启服务部署后 CSS/JS 全部丢失DEBUGFalse 后未处理静态文件用 WhiteNoise 或 Nginx 统一托管静态文件5.3 框架层面的避坑心得再说几个框架层面的细节。Django 里除非要处理文件流下载等场景否则别给所有接口都上 StreamingHttpResponse普通 JsonResponse 完全够用也方便前端统一处理。Flask 自带的开发调试服务器只能用于本地开发上线前务必换成 waitress 或 gunicorn否则并发一大就会出现连接数耗尽。时间处理方面我建议所有接口返回的时间字段统一用 ISO 格式字符串前端直接 new Date() 解析不要返回各种本地化格式否则多终端展示容易乱。时区统一设置为 Asia/ShanghaiDjango 的 USE_TZ 保持开启Flask 端写入时间用 datetime.now() 或 UTC 转本地时间时保持一个标准。数据分析的项目还有一个容易被忽视的坑TOP 排行榜接口的排序一定要在数据库 SQL 层完成前端拿到数据后不要二次排序。尤其接口还带分页时前端排序和分页组合会出现数据错乱排查起来非常费劲。这套系统从设计到上线前后大概用了三周时间。我的体会是技术选型真的不是越新越好要看场景。Flask 和 Django 的组合在一开始被认为有点多余但用下来发现它们各扛各的职责开发效率和运行稳定性都不错。后续想扩展的话可以继续加用户画像分析、库存预警、促销效果评估这些模块。只要数据库表结构当初留好了访问日志和细粒度订单明细扩展空间其实很大。如果让我重做一遍我唯一会改的是把 Django 与 Flask 的公共数据访问层再抽得薄一点其他部分照旧就挺好。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

SQL Server存储过程与触发器实战:从T-SQL语法到数据库设计边界 2026/9/17 17:22:20

SQL Server存储过程与触发器实战:从T-SQL语法到数据库设计边界

简介:西北工业大学《数据库原理》实验报告(第五部分)提供了一份完整的数据库操作实践案例,适合正在学习SQL Server存储过程与触发器的本科学生作为参考。文档围绕视图更名、带参数存储过程创建与加密、系统存储过程查看文本信息展…

阅读更多 →
OpenUSD usdVol 粒子场位置基类 Schema:ParticleFieldPositionBaseAPI 完整解析 2026/9/17 17:22:20

OpenUSD usdVol 粒子场位置基类 Schema:ParticleFieldPositionBaseAPI 完整解析

OpenUSD usdVol 粒子场位置基类 Schema:ParticleFieldPositionBaseAPI 完整解析 【免费下载链接】OpenUSD Universal Scene Description 项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD ParticleFieldPositionBaseAPI 是 Pixar OpenUSD&#xf…

阅读更多 →
AG Kit 静态站点实战:基于 Next.js 16、React 19 与 Tailwind v4 的模板全解 2026/9/17 17:22:20

AG Kit 静态站点实战:基于 Next.js 16、React 19 与 Tailwind v4 的模板全解

AG Kit 静态站点实战:基于 Next.js 16、React 19 与 Tailwind v4 的模板全解 【免费下载链接】ag-kit 项目地址: https://gitcode.com/GitHub_Trending/an/ag-kit 本文以 AG Kit 仓库内置的 App Builder 技能模板(TEMPLATE.md)为骨架&…

阅读更多 →
Notepad-- 跨平台文本编辑器 3 分钟上手:跨文件查找替换与文件对比实战指南 2026/9/17 17:22:20

Notepad-- 跨平台文本编辑器 3 分钟上手:跨文件查找替换与文件对比实战指南

Notepad-- 跨平台文本编辑器 3 分钟上手:跨文件查找替换与文件对比实战指南 【免费下载链接】notepad-- 一个支持windows/linux/mac的文本编辑器,目标是做中国人自己的编辑器,来自中国。 项目地址: https://gitcode.com/GitHub_Trending/no…

阅读更多 →
书匠策AI的毕业论文生成功能:一个把“写论文”变成“填骨架”的学术脚手架 2026/9/17 17:22:20

书匠策AI的毕业论文生成功能:一个把“写论文”变成“填骨架”的学术脚手架

官网:www.shujiangce.com | 微信 公众号 :书匠策AI 一个被反复验证的残酷现实 带过毕业论文的人都知道一个规律:卡住学生的从来不是“写”,而是“不知道怎么开始写”。 选题纠结两周,文献读了一堆却理不出头绪&a…

阅读更多 →
硬件面试宝典2026:重建可迁移的硬件思维操作系统 2026/9/17 17:19:20

硬件面试宝典2026:重建可迁移的硬件思维操作系统

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

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞