拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Django实战拆解:完整版电商系统的模块规划与核心实现

简介这套资源是一份基于Python Django框架开发的完整电商系统源码面向Django学习者与Web开发进阶者适合用于理解电商项目整体架构并直接运行二次开发。项目覆盖商家入驻、商品管理、用户注册与手机验证、购物车、订单结算、模拟支付及省市区街道四级联动地址等核心模块同时配置于Python 3.6环境便于搭建和调试。资源共包含561个文件压缩包大小约96.63MB。其中以图片jpg/png/gif和静态资源css/js/svg/字体文件为主用于页面展示与样式布局70个py文件及pyc文件构成Django项目核心代码18个html为模板页面另有少量json配置文件等整体结构清晰方便按模块查阅。目前已有1771人学习下载适合初学者从整体上了解Django的MVT模式、ORM操作及前后端协作流程也可供开发者借鉴商品、订单、地址联动等功能的实现思路是快速上手Django电商开发的实用实例。 最近总有人问我Django 到底能不能撑起一个“完整版”的电商系统。我的答案一直是能而且很合适。但前提是你得先把“完整版”这三个字定义清楚——不是功能堆得越多越好而是商品、购物车、订单、支付、库存、权限、后台管理、数据统计这条主链路必须闭环。我做过几个从零到上线的电商项目中间踩了不少坑这篇就把我总结出来的模块划分、数据建模、关键实现和部署心得一次讲透。内容偏实战适合已经有 Django 基础、正准备做完整项目练手或接电商单子的朋友。1. 从零规划完整版电商到底该先做哪些模块1.1 先给“完整版”划边界我接到电商项目需求时第一件事不是动手写代码而是和需求方一起把模块边界定下来。一个能真正上线的电商系统至少要包含这几块用户端注册登录、商品浏览、购物车、下单支付、订单查询、售后申请、管理端商品管理、库存管理、订单处理、发货运单、退款审核、支撑系统支付回调、消息通知、文件存储、数据统计。如果你是个人学习项目我建议你别一上来就做秒杀、优惠券、多级分销这种衍生功能先把主链路跑通。我见过太多人第一天就研究如何对接支付宝花呗分期结果购物车和订单还没写完。一个合格的 MVP 完整版先把用户、商品、购物车、订单、支付、库存这套主干做完就已经能抵得上不少商业项目的基础盘了。1.2 为什么选 Django 做电商Django 做电商的优势不在性能天花板而在开发效率和内置能力。电商系统有大量数据关联和权限控制需求Django 的 ORM、Admin 后台、认证系统、表单校验几乎是开箱即用。它的 ORM 让我在迁移表结构、写复杂查询时省下大量时间自带 Admin 可以快速搭建运营后台甚至在早期直接充当管理界面。还有一个经常被忽略的点Django 的项目结构天然适合电商这种多模块应用。你可以把用户、商品、购物车、订单、支付拆成独立 app各自有 models、views、serializers、services业务边界清晰后期新同学接手也不会迷路。如果用粗暴的单文件应用堆代码做到一半你连自己的路由都记不住。1.3 技术栈的整体选型思路我习惯的电商栈是这样Django DRF前后端分离或 Django Templates服务端渲染二选一数据库用 PostgreSQL 或 MySQL绝不用 SQLite 上生产缓存用 Redis存 Session、热点商品、验证码对象存储用 OSS/S3/MinIO管理商品图片和视频异步任务用 Celery处理发邮件、短信、订单超时关闭等场景。前后端分离和模板渲染的取舍我放到第 3 章细说。这里只提醒一点如果以后你要做小程序或 App后端接口是逃不掉的所以哪怕现在只做 Web 端我也建议把核心业务逻辑放在 DRF 风格的 API 里网页端可以调用同一套接口。这样后期扩展成本很低不用推翻重来。2. 商品模块的数据模型SPU 和 SKU 是第一步2.1 SPU 与 SKU先把货和款分清楚做电商系统最忌讳的就是商品表里一行一个商品、颜色尺码用逗号拼字符串。正经的设计一定要拆 SPU标准化产品单元和 SKU库存量单位。简单说SPU 是“商品”SKU 是“具体可下单的款”。同一件T恤SPU可以有不同的颜色和尺码组合每种组合就是一个 SKU拥有自己的价格、库存、规格编码。如果不拆开后面做购物车、库存扣减、订单快照时会痛不欲生。我实际用过的模型结构大致是这样class Spu(models.Model): name models.CharField(商品名称, max_length128) category models.ForeignKey(Category, on_deletemodels.PROTECT) main_image models.ImageField(主图, upload_tospu/main/%Y/%m/) detail models.TextField(详情, blankTrue) class Sku(models.Model): spu models.ForeignKey(Spu, on_deletemodels.CASCADE, related_nameskus) spec models.JSONField(规格, defaultdict) # 如 {颜色: 黑, 尺码: L} price models.DecimalField(售价, max_digits10, decimal_places2) stock models.PositiveIntegerField(库存, default0) sku_code models.CharField(SKU编码, max_length64, uniqueTrue)规格用 JSONField 存最省事查询用 like 或精确匹配都能覆盖大多数场景。要注意给sku_code加唯一约束这是后续对接 ERP、财务报表和物流系统的钥匙。2.2 价格精确性为什么用 Decimal 而不是 Float每个电商项目我都反复强调价格字段必须用DecimalField不要用FloatField。这不是洁癖而是浮点数的二进制存储机制决定了它算不了金融金额。试着在 Python 里跑一下0.1 0.2结果是0.30000000000000004放到订单金额上就是灾难。用DecimalField(max_digits10, decimal_places2)能保证数据库层面就约束精度。所有金额计算在 Python 和数据库层都用 Decimal 类型完成前端展示才可能分毫不差。注意DecimalField的max_digits要按业务规划好电商一般到 10 位足够如果你做的是大额 B2B 交易至少留到 12 位以上。2.3 多图与视频上传本地存储和对象存储的区别电商商品不可能只有一张图视频展示也是现在很多实物商品的标配。Django 处理上传本地开发只用配置MEDIA_ROOT和MEDIA_URL就好了字段上用ImageField、FileField直接搞定。生产环境我强烈建议改用对象存储用django-storages配置 S3/OSS 兼容接口。原因有两条一是本地磁盘存文件后应用实例因为磁盘故障需要重建时数据会丢二是后期部署多台应用实例做负载均衡时文件必须统一存在一个共享存储上否则用户在 A 机器上传的图片请求落到 B 机器上就 404 了。上传视频还有一个容易忽略的点一定要做格式和大小限制。视频文件动辄几十 MB如果直接塞进对象存储前端播放体验和运营成本都会很难看。我一般会在前端做压缩和分片上传后端只接收规定格式和大小范围的文件再配合一个异步转码任务把它压成多码率的流媒体格式。这块用 Celery 配合 ffmpeg 实现很成熟属于进阶功能但做了之后商品详情页的视频体验能上一个台阶。3. 用户、登录与购物车别让状态边界坑了你3.1 自定义 User 模型从项目第一天就做Django 自带 User 模型在简单场景下够用但电商项目几乎必然要加手机号、昵称、头像、积分等字段。所以我强烈建议项目创建后第一时间就自定义一个继承AbstractUser的 User 模型哪怕暂时什么都不加。这个决策必须在第一次python manage.py migrate之前做否则后面替换 User 模型会非常痛苦——涉及大量外键和事务脚本迁移市面上没有完美的自动方案。我当年接手过一个半成品项目就是先跑完了默认迁移后来加phone字段时只能通过新建用户表、重构关联关系的方式绕过去白白消耗了两天时间。自定义方式class User(AbstractUser): phone models.CharField(手机号, max_length20, blankTrue, nullTrue, uniqueTrue) avatar models.ImageField(头像, upload_touser/avatar/%Y/%m/, blankTrue, nullTrue)记得在settings.py里加一行AUTH_USER_MODEL users.User。3.2 登录态管理Session 还是 JWT这个问题我每次都会被问到。我的判断标准很简单纯 Web 端、用 Django 模板渲染直接使用 Django 内置 Session 认证简单可靠配合 Redis 做 Session 存储性能也不差。要做小程序或 App 端或者前后端完全分离且涉及跨域、多端登录用 JWT具体库就是djangorestframework-simplejwt。JWT 方案有个坑access token 有效期不能设太长一般 15 分钟到 2 小时refresh token 可以设 7 到 14 天但要走刷新接口。另外JWT 是无状态的一旦签发在过期前你是没法主动让它失效的所以用户被禁言、封号这类操作需要自己在数据库里维护一个“用户状态”字段做二次校验不能只依赖 token。3.3 游客购物车与用户购物车合并时机要选对购物车是电商系统最容易写得乱的部分。我常用的设计是用户未登录时购物车数据存 Cookie或 Redis用用户浏览器指纹做 key登录后购物车数据落数据库表结构核心就是user_id、sku_id、quantity三个字段。登录时要把游客购物车合并到用户购物车这一步要注意合并策略同 SKU 数量相加而不是覆盖如果用户购物车里已有这个 SKU也需要做数量汇总。Cookie 还有个隐患是容量有限大约 4KB塞太多商品会溢出所以 Cookie 里只存 sku_id 和 quantity商品名称、价格、图片一律进入购物车页再实时查询。这样既省容量又能保证价格和库存是现查的不会出现购物车显示的价格与下单时的价格不一致。4. 订单链路与支付回调状态机设计是核心中的核心4.1 订单状态机先画图再写代码订单模块是整个电商系统的地基状态流转不清后续所有功能都是空中楼阁。我每做一个电商项目都会先拉几个人一起把状态机画清楚。最常用的状态序列是待付款 → 已付款/待发货 → 已发货/待收货 → 已完成同时有已取消、售后中、已退款这几个分支。Django 里实现状态机最轻量的做法是定义TextChoices再写一个状态变更方法集中校验合法性class OrderStatus(models.TextChoices): PENDING_PAYMENT pending_payment, 待付款 PAID paid, 已付款 SHIPPED shipped, 已发货 COMPLETED completed, 已完成 CANCELLED cancelled, 已取消 REFUNDED refunded, 已退款 class Order(models.Model): status models.CharField( 订单状态, max_length20, choicesOrderStatus.choices, defaultOrderStatus.PENDING_PAYMENT, ) ...状态迁移不要到处直接改 status 字段我建议在每个 model 里实现一个transition_status(new_status)方法里面用字典定义合法迁移路线非法路线直接抛异常。这样运营后台和用户端无论从哪个入口操作订单都能保证状态不会“跳步”。4.2 扣库存与防超卖锁行与事务缺一不可只要是真实项目库存超卖就是必须正面解决的问题。最直接的方案是数据库行锁 事务。我写订单接口时核心逻辑是在一个事务里先select_for_update()锁定 SKU 行再判断库存是否足够够就扣减同时生成订单。select_for_update()会在这条事务提交前把被选中的行锁住其他并发请求只能排队等待。from django.db import transaction transaction.atomic def create_order(user, sku_id, quantity): sku Sku.objects.select_for_update().get(pksku_id) if sku.stock quantity: raise ValueError(库存不足) sku.stock - quantity sku.save() return Order.objects.create( useruser, skusku, quantityquantity, total_amountsku.price * quantity, )这个方案在单体应用、单数据库实例下完全够用。不要一上来就上 Redis 预减库存 MQ 异步扣库存那套分布式事务的复杂度远高于它解决的问题除非你的日订单量真的大到数据库扛不住再考虑重构。4.3 支付回调幂等与签名校验是最重要的两件事订单生成后跳转支付接下来就是第三方支付平台的回调通知。这里我踩过的最大教训是回调处理必须幂等否则同一笔支付通知发两次你的订单就被重复处理了。幂等方案很简单支付回调表里给order_no transaction_id建唯一约束回调处理时先插入记录如果插入冲突说明已经处理过直接返回成功。这样天然挡住重复请求。签名校验就更不用说了支付平台回传的签名必须用平台公钥或密钥验签通过后才允许修改订单状态。我见过有人跳过验签直接信任回调参数结果被恶意伪造支付通知刷单的案例线上事故级别。每次回调处理完成后顺手把原始报文和验签结果存到支付流水表里方便以后排查对账问题。对账可以用 Celery 定时任务每天凌晨把本地订单和支付平台账单做一次比对金额不一致的订单进入人工审核。5. 查询性能与数据指标功能写完不等于能用5.1 ORM 查询优化的几个实战点商品和订单数据量上来之后Django ORM 写不好数据库是真的会挂。我常用的优化手段有这几个列表页查询必须用select_related和prefetch_related解决 N1 问题。商品列表涉及分类、SKU、主图等多张表关联能用一条查询拿到的绝不循环里查。订单查询需要关联用户、地址、商品快照时用values()或annotate只取需要的列避免把大字段如详情 HTML全部加载出来。大表删除和更新不要一次性filter(...).delete()分批处理比如循环每次取 1000 条 id再 delete避免锁表和事务日志膨胀。还有一个很多新手不知道的刚需操作ORM 删除对象时的级联行为。on_deletemodels.CASCADE虽然省事但电商相关的业务数据我几乎不用 CASCADE而是用SET_NULL或PROTECT。比如订单引用了商品 SKUSKU 被删了订单详情里的 SKU 外键如果置空或报错都会影响历史订单展示。更稳妥的方式是订单里冗余一份商品名称、单价、图片快照SKU 本身用软删除这样历史订单数据永远完整可回溯。5.2 压测的意义与常见瓶颈“电商压测”这个词在热搜里很靠前说明大家已经意识到上生产之前要做性能验证。我自己常用的工具是 locust纯 Python和 Django 技术栈同源写压测脚本几乎没有学习成本。压测要看的核心指标不是并发数而是两个P95 响应时间和错误率。我一般会压两个场景商品详情页刷新和提交订单。如果发现大量 504 或响应时间飙升先查数据库慢查询日志再看 Gunicorn worker 是否被打满最后看 Redis 命中率。很多情况下加了缓存和索引之后同一套代码能从每秒几十个请求提升到几百个。Gunicorn worker 数量我习惯按2 * CPU 核心数 1来配然后在压测过程中慢慢调。扛不住时先加 worker再加数据库连接池最后才考虑拆服务和上消息队列——顺序很重要别一上来就想上微服务。5.3 电商数据指标销售分析不是一门玄学既然做的是完整版电商运营侧的数据指标系统也得做。最常用的是 GMV、订单量、客单价、转化率、商品动销率、复购率这一组。Django 里做 GMV 统计非常顺手聚合查询一把梭from django.db.models import Sum, F, DecimalField from django.db.models.functions import TruncDate daily_gmv ( Order.objects.filter(statusOrderStatus.PAID) .annotate(dayTruncDate(paid_at)) .values(day) .annotate(gmvSum(F(total_amount), output_fieldDecimalField())) .order_by(day) )转化率需要把浏览、加购、下单、支付这几个环节的数字串起来建议在上游埋好事件表。我一般会建一张UserActionLog记录user_id、action_type、target_id、created_at后续无论是做转化漏斗还是用户行为分析都可以直接在这张表上聚合。数据量大了再做离线数仓前期没必要。6. 部署上线与日常维护把 Django 真正跑起来6.1 本地开发环境venv、uv 与依赖管理开发环境管理这件事看似基础实际上团队协作里最容易出问题。早期我用python -m venv venv创建虚拟环境配合pip freeze requirements.txt锁版本。后来发现pip freeze会把一些无关传递依赖也打进去而且安装速度慢我换成了 uv。uv 现在基本成了我所有 Python 项目的标配工具。它创建虚拟环境、安装依赖的速度比 pip 快一个数量级配置pyproject.toml后依赖管理清晰很多。基本用法uv venv venv source venv/bin/activate uv pip install django djangorestframework mysqlclient redis celery如果你已经不用某个旧虚拟环境了直接删除目录就行rm -rf venv。别把虚拟环境目录提交到 Git在.gitignore里加一行venv/这是所有 Python 项目协作的基本素养。6.2 生产部署Gunicorn Nginx Supervisor 的组合生产部署我首选的是比较传统但稳定的一套Nginx 做反向代理和静态文件服务Gunicorn 跑 Django 动态进程Supervisor 守护 Gunicorn 进程防止意外退出后长时间没人拉起。数据库用 PostgreSQL 或 MySQL部署在单独的机器或云数据库服务上。Nginx 最主要的作用是处理静态文件和媒体文件、缓冲和转发请求、终结 TLS 证书。配置里要特别注意设置合理的client_max_body_size不然用户上传大图或视频会直接被 Nginx 返回 413。Supervisor 配置里我习惯把autorestarttrue打开stopasgrouptrue保证重启时能把 Gunicorn worker 都退干净。作为一个系统服务尽量用 systemd 或 Supervisor 管理不要裸跑python manage.py runserver——那玩意是开发调试用的性能和稳定性都不适合生产。有人问我宝塔面板能不能用我的回答是能用很多小项目用宝塔确实能大幅度降低运维门槛但你要知道花哨的面板背后是什么。如果只是个人项目或小公司内部系统宝塔省心省事如果客户要求可维护性和安全审计建议还是用云厂商托管服务和命令行配置日志、告警、权限控制都正规得多。6.3 上线后最容易忽略的几件事项目真正上线之后有几件事特别容易被忽视。第一Django 的DEBUG False必须设置否则任意页面报错都会把完整堆栈和配置泄露给访问者。第二SECRET_KEY、数据库密码、各平台密钥绝不能写死在代码里用环境变量或配置中心管理最好定期轮换。第三生产环境的ALLOWED_HOSTS要精确到域名列表只接受你认可的主机头。日志这块我也要吃一堑长一智。Django 默认的日志配置在生产环境几乎不可用我一般会配handlers: {file: {class: logging.handlers.RotatingFileHandler, ...}}按天滚动保留 30 天同时把异常和关键业务操作下单、支付回调、后台操作打进独立日志文件。出了问题能快速定位到具体时间点的具体操作省下的排查时间远大于配置日志的那几分钟。7. 一些想单独说的实战心得最后分享几个我个人的体会不一定写在任何官方文档里但都是真金白银换来的经验。第一个是数据库迁移一定要规范。每次改 models 前先改代码、再makemigrations、再migrate迁移文件全部提交到版本库。不要手动去数据库加字段否则团队其他人的迁移会直接乱掉。第二个是 Admin 后台值得投入时间定制。Django 自带的 Admin 是特别好的运营工具花点时间配置list_display、list_filter、search_fields、inlines可以让运营同学自己处理很多日常操作比如改商品排序、处理退款申请减少开发人员的打断式需求。第三个是接口规范和错误码要从第一天定好。电商项目后期免不了要接第三方、合作方甚至自己家公司的小程序团队。如果你每次接口报错都返回不一样的格式联调时对方会崩溃。我习惯统一用{code: 0, message: ok, data: {}}这种结构业务错误码从 1000 开始分配文档同步更新配合 DRF 的 exception handler 统一包装异常返回值。第四个是不要太迷信最新版框架。我主力用的是 Django 4.2 LTS它维护期长、生态兼容性好。新版本特性再多如果依赖库还没跟上踩坑成本远大于收益。做电商项目追求的是稳定交付不是炫耀技术栈最新。做完整版电商这件事听着工程量大但只要模块边界清晰、数据模型提前设计好、状态流转不糊弄它其实比想象中要可控。Django 能给你的不仅是快速开发的能力更是一套约定俗成的工程纪律。如果你正在做或准备做自己的电商项目希望这篇文章能帮你绕开我踩过的那些坑把时间花在真正有价值的功能打磨上。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门