ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python购物商城管理系统源码实战:从环境配置到订单与缓存优化

Python购物商城管理系统源码实战:从环境配置到订单与缓存优化 简介基于Python开发的购物商城管理系统源码是一套面向初中级Web开发者的完整项目实例围绕商家与顾客两类角色展开覆盖商家注册登录、店铺信息管理、商品添加删除与更新、交易记录查看以及顾客注册登录、收货信息维护、商品搜索购买、订单取消等典型业务能够帮助读者在真实源码中理解商城系统的角色划分、模块组织与前后端请求处理流程。整个压缩包共60个文件、约417KB包含23个Python源码文件、17个UI界面文件、17张界面图片另附SQL数据库脚本、说明文档及许可证。Python源码对应服务端与客户端逻辑UI文件用于还原操作界面SQL脚本定义了用户、商品、订单等数据表及其外键关联关系目录结构清晰便于按模块逐个阅读。目前已有2434人浏览学习。项目在用户认证、权限区分、订单事务与数据库多表关联等方面均提供了可运行的实践代码读者可以结合UI文件和数据库脚本追踪从页面操作到后端处理再到数据落地的完整链路同时也可借助源码学习登录状态的保持、商品增删改查的实现思路以及下单与取消订单时的事务处理对提升Python Web开发实战能力很有帮助。1. Python购物商城管理系统源码先看清它能不能直接落地做购物商城类系统最烦的不是写商品列表而是把订单、库存、用户这三件事理顺。很多人拿到一份《基于Python的购物商城管理系统源码.zip》第一反应是解压看目录第二反应是跑不起来第三反应是丢进收藏夹吃灰。这份资源的价值在于它把商城最核心的用户端和管理端都搭好了框架你不需要从零去写注册登录、商品分类、购物车和订单状态流转只需要在已有代码基础上做配置和二次开发。适合两类人碰一类是刚学完Python想找个完整项目练手的开发新人另一类是要在短期内给学校或小团队交付一个可演示商城系统的从业者。先说清楚这是一份能改动、能跑通、能演示的工程代码不是教学PPT拿到手就要按能上线的标准去验收。2. 跑通整套源码前的环境准备版本选对少走两小时弯路2.1 技术栈判断这份源码大概率是 Django 还是 Flask在解压源码之前先花两分钟看目录结构。如果里面有manage.py那基本是 Django 工程如果只有app.py或main.py加一堆路由文件那走的是 Flask 路线。以「购物商城管理系统」这类标题命名的资源包绝大多数情况下用的是 Django自带 admin 后台是它最大的优势——商城的管理端商品上架、订单处理可以直接依托 admin 改省掉大量手写管理页面的时间。我一般会先用tree /fWindows或ls -lRLinux看一遍项目根目录重点确认三个文件是否存在requirements.txt依赖清单、manage.pyDjango 入口、README.md作者说明。如果requirements.txt缺失后面安装依赖会非常痛苦因为你不清楚作者用了哪个版本。2.2 Python 与虚拟环境的版本选择写商城系统时最怕的玄学问题本机能跑换台机器就挂。根因十有八九是 Python 版本和 Django 版本不匹配。下载这份源码后先在虚拟环境里锁版本不要直接装到全局环境。# 创建 Python 3.10 虚拟环境Windows py -3.10 -m venv venv # Linux / macOS python3.10 -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # Linux / macOS: source venv/bin/activate # 查看当前 Python 版本 python --version虚拟环境的好处是把这份源码的依赖和系统其他项目隔离不会因为别的项目升级了某个库这边直接跑崩。Python 3.10 是目前购物商城类项目兼容性较好的版本Django 4.x 支持 3.10 以上Django 3.2 LTS 也支持到 3.10如果源码里的 Django 版本低于 3.2建议升级到 3.2 LTS这是兼容性和稳定性最均衡的版本。2.3 requirements.txt 依赖清单的处理商城系统的依赖通常集中在 Django 本身、数据库驱动、图片处理库这几块。装依赖时不要pip install -r requirements.txt一把梭先打开文件看一眼再决定。# 先看依赖文件内容 cat requirements.txt # 然后安装 pip install -r requirements.txt如果文件里没有版本号比如只写了Django安装的是当前最新版很可能与源码不兼容。常见做法是手动指定版本安装pip install Django3.2.25 mysqlclient2.1.1 Pillow10.0.0Django 3.2 是 LTS 版本安全更新到 2024 年适合商城这类需要长期维护的系统mysqlclient 是让 Django 连 MySQL 的关键库Windows 下经常装不上后面专门讲Pillow 负责商品图上传和缩略图处理商城系统离不开它2.4 数据库选型与初始迁移源码默认可能用的是 SQLitesettings.py里DATABASES配置如果写的是sqlite3SQLite 适合本地演示但商城系统要达到可演示甚至可上线的程度建议换成 MySQL。切换到 MySQL 之前先确认settings.py里的连接配置# settings.py 数据库配置片段 DATABASES { default: { ENGINE: django.db.backends.mysql, # 切换为 MySQL 引擎 NAME: shop_db, # 数据库名需要提前创建 USER: root, # 数据库账号 PASSWORD: your_password, # 数据库密码 HOST: 127.0.0.1, # 本地连接 PORT: 3306, # MySQL 默认端口 OPTIONS: { charset: utf8mb4, # 商品名可能带 emoji用 utf8mb4 } } }配置完成后执行迁移命令把模型映射成数据库表python manage.py makemigrations python manage.py migrate python manage.py createsuperusermakemigrations会根据 models.py 生成迁移脚本如果报没有检测到变化说明源码里迁移文件已经存在跳过这一步直接 migratemigrate是真正建表的过程执行完可以用python manage.py showmigrations验证所有迁移是否到位createsuperuser创建管理后台账号密码要求至少 8 位别用测试密码偷懒后面进 admin 后台全靠它跑完这些源码才算真正在你的机器上活过来。3. 商城系统的数据模型架构读懂订单、商品、用户三者的关系再动手3.1 核心模型的字段设计逻辑购物商城管理系统的代码量看起来大拆开就是三张核心表用户表、商品表、订单表。源码里的 models.py 无论写得多复杂本质上都是这三张表在互相关联。拿到源码别急着改业务逻辑先把每个模型读一遍重点是外键关系和字段类型。# models.py 中常见模型结构从源码提炼后的典型写法 from django.db import models from django.contrib.auth.models import User class Category(models.Model): 商品分类 name models.CharField(max_length50, verbose_name分类名称) parent models.ForeignKey(self, nullTrue, blankTrue, on_deletemodels.CASCADE, verbose_name父级分类) class Meta: db_table shop_category verbose_name 商品分类 class Product(models.Model): 商品表 name models.CharField(max_length200, verbose_name商品名称) category models.ForeignKey(Category, on_deletemodels.CASCADE, verbose_name所属分类) price models.DecimalField(max_digits10, decimal_places2, verbose_name售价) stock models.IntegerField(default0, verbose_name库存) image models.ImageField(upload_toproducts/, nullTrue, blankTrue, verbose_name商品图) status models.BooleanField(defaultTrue, verbose_name是否上架) created_at models.DateTimeField(auto_now_addTrue, verbose_name创建时间) class Meta: db_table shop_product verbose_name 商品这里最值得注意的两个设计price用的是DecimalField而不是FloatField这是商城项目绝对不能妥协的点——浮点数计算金额会产生精度误差DecimalField(10, 2)保证两位小数的精确存储Product和Category用外键关联分类删除时默认级联删除商品如果不想删商品把on_delete改成SET_NULL并允许字段为空。3.2 订单状态机的设计思路订单表是整个系统中字段最多、最容易翻车的部分。源码里订单状态一般用整数字段加choices实现这样比字符串存储更规范class Order(models.Model): 订单表 ORDER_STATUS ( (0, 待付款), (1, 待发货), (2, 待收货), (3, 已完成), (4, 已取消), ) user models.ForeignKey(User, on_deletemodels.CASCADE, verbose_name下单用户) order_no models.CharField(max_length32, uniqueTrue, verbose_name订单编号) total_amount models.DecimalField(max_digits10, decimal_places2, verbose_name订单总金额) status models.IntegerField(choicesORDER_STATUS, default0, verbose_name订单状态) created_at models.DateTimeField(auto_now_addTrue, verbose_name下单时间) class Meta: db_table shop_order verbose_name 订单 class OrderItem(models.Model): 订单明细记录下单时的商品快照 order models.ForeignKey(Order, related_nameitems, on_deletemodels.CASCADE, verbose_name所属订单) product models.ForeignKey(Product, on_deletemodels.CASCADE, verbose_name商品) price models.DecimalField(max_digits10, decimal_places2, verbose_name下单时单价) quantity models.IntegerField(default1, verbose_name购买数量)订单和订单明细为什么要拆成两张表因为一张订单里可能买了三件不同商品订单表记总价和状态明细表记每件商品的快照。price字段在 OrderItem 里保存的是下单那一刻的价格不是直接关联商品表的实时价格——如果后台改价了订单记录不跟着变否则对账时候就扯不清了。3.3 数据模型常见的四个问题排查migrate报Table xxx already exists这个报错是迁移文件与数据库状态不一致导致的。不要删数据库执行python manage.py migrate --fake-initial让 Django 跳过已经存在的表商品表里image字段没有图片路径检查settings.py里是否配置了MEDIA_ROOT和MEDIA_URL没有配置的话上传功能看着能用但刷新后会 404订单明细查不到对应商品OrderItem 的product外键如果用了on_deletemodels.CASCADE后台一旦删掉商品历史订单明细也跟着消失这是设计缺陷。正确做法是on_deletemodels.SET_NULL, nullTrue保留订单记录中文字段乱码数据库建库时字符集必须是utf8mb4而不是utf8同时检查 MySQL 配置文件的character-set-serverutf8mb44. 把核心业务跑通购物车、下单、库存扣减的实现细节4.1 购物车的两种落地方式商城系统的购物车源码里有两种实现路线基于 Session 的和基于数据库表的。Session 方案适合未登录用户但用户换设备就丢数据库方案适合登录用户但需要额外建表。现代商城一般把两种方案结合——用户未登录时把购物车放 Session登录后同步到数据库。# cart.py —— 基于 Session 的购物车核心逻辑 class Cart: def __init__(self, request): self.session request.session cart self.session.get(cart, {}) if not cart: cart {} self.cart cart def add(self, product_id, quantity1): 添加商品到购物车 product_id str(product_id) if product_id in self.cart: self.cart[product_id][quantity] quantity else: self.cart[product_id] { quantity: quantity, price: str(Product.objects.get(idproduct_id).price) } self.save() def save(self): self.session[cart] self.cart self.session.modified True # 告诉 Django session 已变更 def remove(self, product_id): product_id str(product_id) if product_id in self.cart: del self.cart[product_id] self.save()这个实现的关键在最后一行self.session.modified True如果你忘了设置 Django 会认为 session 没变浏览器刷新后购物车内容又变回去了——这是 Session 购物车最常见的坑。price存的是字符串因为要放 session 里序列化数值类型反而容易在 JSON 编码时报错。4.2 下单逻辑事务、锁与库存扣减下单是商城系统最核心也最容易翻车的环节。没有事务保护的下单逻辑在高并发下会出现超卖——库存剩 1 件10 个人同时下单全都成功了。# views.py 下单函数基于 Django 事务 from django.db import transaction from django.shortcuts import get_object_or_404 transaction.atomic def create_order(request, cart_items): 下单并扣减库存整个过程在同一个事务里执行 user request.user total_amount 0 order None try: # 第一步创建订单主表 order Order.objects.create( useruser, order_nogenerate_order_no(), # 生成唯一订单号 total_amount0 # 先用 0 占位明细算完再更新 ) # 第二步逐商品扣库存、写明细 for item in cart_items: product get_object_or_404(Product, iditem[product_id]) if product.stock item[quantity]: raise ValueError(f商品 {product.name} 库存不足) # 在事务里执行原子更新避免并发超卖 updated Product.objects.filter( idproduct.id, stock__gteitem[quantity] ).update(stockmodels.F(stock) - item[quantity]) if updated 0: raise ValueError(f商品 {product.name} 库存不足) OrderItem.objects.create( orderorder, productproduct, priceproduct.price, quantityitem[quantity] ) total_amount product.price * item[quantity] # 第三步回填订单总金额 order.total_amount total_amount order.save() return order except Exception as e: # 事务块中抛出异常会自动回滚 raise etransaction.atomic是 Django 的事务装饰器函数内任何一步报错整个订单和库存扣减一起回滚Product.objects.filter(...).update(...)配合stock__gte条件是防止超卖的关键动作它把「检查库存」和「扣库存」合成了一个原子操作stock__gteitem[quantity]表示库存大于等于购买数量才更新更新返回 0 说明这行没被改到说明库存已被别人抢完4.3 订单状态流转的权限判断管理后台中「发货」「完成订单」这类操作要在视图函数里加权限校验不能只靠前端隐藏按钮。源码里如果是用 Django admin 开发的在 ModelAdmin 里重写has_change_permission即可控制谁能改订单状态如果是自写管理页面需要手动判断request.user.is_staff再加一层角色判断。给订单发货这种状态变更动作应该在 Model 里封装一个方法而不是在视图里直接order.status 2; order.save()。统一走方法的好处是以后要加状态流转日志只需要改一个地方。5. 避坑指南这份商城源码踩过的五个典型坑5.1 图片上传后访问 404现象后台添加商品时上传了图片前台页面上图片裂开打开图片地址直接 404原因settings.py里只配了MEDIA_URL没配MEDIA_ROOT或者主路由urls.py没有把 media 目录暴露到开发服务器解决在settings.py里写MEDIA_ROOT os.path.join(BASE_DIR, media)然后在urls.py里加一段开发环境的静态路由from django.conf import settings from django.conf.urls.static import static urlpatterns static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)这段代码只在开发环境用部署到 Nginx 之后由 Nginx 直接托管 media 目录。5.2 mysqlclient 在 Windows 上装不上现象pip install mysqlclient报Microsoft Visual C 14.0 is required然后整个依赖安装流程卡住原因mysqlclient 在 Windows 上需要预编译的 C 库pip 现场编译会失败解决去https://pypi.org/project/mysqlclient/#files下载对应 Python 版本的.whl文件然后用pip install 本地文件路径安装。或者直接改用pymysql在settings.py里加import pymysql pymysql.install_as_MySQLdb()这样 Django 连接 MySQL 就能用 pymysql 当替身不过生产环境建议还是用 mysqlclient性能更稳。5.3 迁移记录与数据库不同步现象执行python manage.py migrate报django.db.migrations.exceptions.InconsistentMigrationHistory或者直接提示某张表已存在原因源码包里自带了一份数据库文件比如db.sqlite3表结构和 migrations 记录对不上或者之前迁移失败留了半截解决如果本地数据不重要直接删除数据库文件SQLite 的db.sqlite3重新makemigrationsmigrate。如果数据重要备份后逐条核对python manage.py showmigrations把不一致的记录用--fake标记掉5.4 管理后台无法登录现象createsuperuser执行成功但 admin 页面上输入账号密码报错提示用户名或密码不正确原因大概率是密码强度不够Django 默认密码校验器拒绝弱密码但 createsuperuser 有时会静默失败也可能你输入用户名时带了空格解决在 Django shell 里强制重置密码python manage.py shell -c from django.contrib.auth.models import User; u User.objects.get(usernameadmin); u.set_password(new_password); u.save()set_password方法会经过 Django 的密码哈希代替 admin 命令清理掉密码校验环节的问题。5.5 前台页面样式丢失现象页面能打开但全是裸 HTMLCSS 完全没加载原因settings.py里DEBUG FalseDjango 不再自动提供静态文件服务解决开发调试时把DEBUG改为True先看效果需要对外演示时执行python manage.py collectstatic把静态文件收拢到STATIC_ROOT交给 Nginx 或 IIS 托管python manage.py collectstatic注意STATIC_ROOT一定要指向一个空目录不然 collectstatic 会把旧文件和新文件混在一起页面样式变得不三不四。6. 再进阶一步给商城加上缓存与并发保护商城系统跑通以后下一步值得做的事是给商品列表页加缓存。Django 项目最常见的性能瓶颈就是数据库查询——商品列表、分类导航这些访问频率高、数据变化少的内容完全可以用 Redis 缓存扛住。先在依赖里引入 django-redis然后配置缓存后端# settings.py 缓存配置 CACHES { default: { BACKEND: django_redis.cache.RedisCache, LOCATION: redis://127.0.0.1:6379/1, # 使用 1 号数据库 OPTIONS: { CLIENT_CLASS: django_redis.client.DefaultClient, } } }然后在商品列表视图里用cache_page装饰器简单粗暴from django.views.decorators.cache import cache_page cache_page(60 * 15) # 缓存 15 分钟 def product_list(request): products Product.objects.filter(statusTrue).select_related(category) return render(request, shop/product_list.html, {products: products})缓存时间别设太长商城商品价格和库存是动态的缓存 15 分钟已经能消化 80% 的重复请求。要注意的是后台修改商品价格后用户最多 15 分钟内看到的还是旧价格如果不能接受就把缓存时间降到 5 分钟或者在商品保存时主动清除缓存from django.core.cache import cache def product_save(sender, instance, **kwargs): cache.delete(product_list_cache_key) from django.db.models.signals import post_save post_save.connect(product_save, senderProduct)用信号量在商品保存后自动清缓存比手动清缓存可靠得多——不用每次改完商品还记得去删缓存。这套信号方案加上 Redis 之后商品列表页的数据库查询量会直接降一个量级演示时候打开页面秒开感官上完全不一样。再配合一个简单的并发验证方法用abApache Bench或wrk对商品详情页压 100 个并发请求看响应时间的变化。ab -n 1000 -c 100 http://127.0.0.1:8000/product/1/-n 1000表示总共发 1000 个请求-c 100表示同时 100 个并发压测前记录平均响应时间和失败率加完缓存再压一遍数据会非常直观。如果压测时出现订单创建失败或库存异常回头去查第 4 章的下单事务逻辑——那才是商城系统的命门。商城系统的坑十有八九不是代码本身而是环境与数据一致性。从那以后我每次拿到源码包都强制走一遍「虚拟环境 → 依赖检查 → 迁移 → 下单事务验证 → 压测」这套流程不跑完不敢给客户演示。希望帮到你。本文还有配套的精品资源点击获取
返回列表