ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Django商城项目实战:从核心架构到部署优化的完整开发指南

Django商城项目实战:从核心架构到部署优化的完整开发指南 简介这是一套基于Python Django框架开发的完整电商商城项目源码面向Web后端初学者与Django进阶开发者可用于学习典型B2C商城的核心业务逻辑与工程实践。资源包含403个文件主体为53个Python后端代码文件含models、views、urls等模块、11个HTML模板页、8个CSS样式文件如proList.css、detail.css、login.css等体现多页面布局、以及293张商品图片素材整体压缩包33.44MB结构清晰覆盖用户认证、商品展示、购物车、订单管理等关键功能模块。已有3684人下载学习适合通过真实项目理解Django MTV架构、ORM建模、模板渲染、静态资源组织及前后端协同开发流程是开展课程设计、毕业设计或技术面试准备的实用参考范例。1. 项目概述一个Django商城项目的核心价值最近在整理硬盘翻出来一个几年前用Django写的商城项目源码打包成了商城项目源码.zip。这个项目虽然不是什么惊天动地的架构但麻雀虽小五脏俱全从用户注册登录到商品下单支付再到后台管理整个电商的核心链路都跑通了。对于想从零开始理解一个Web应用是如何构建特别是想深入Django这个“大而全”框架的朋友来说这个源码包的价值可能比看十篇教程都来得实在。Django在国内Web开发领域的应用非常广泛尤其是在需要快速构建稳健后台管理系统的场景下它的ORM、Admin、表单和认证系统能帮你省下大量重复造轮子的时间。这个项目就是一个典型的例子它没有追求最新最炫的技术栈而是扎扎实实地用Django的核心组件解决了一个商城系统的基本问题。无论你是刚学完Python语法想找个实战项目练手还是已经有一定基础想看看一个完整项目的代码组织逻辑这份源码都能提供一个清晰的参考。2. 项目整体架构与设计思路拆解2.1 技术选型与架构模式这个项目采用了经典的MVC在Django中更准确地说是MTVModel-Template-View架构模式。选择Django而非其他框架如Flask或FastAPI核心考量在于其“开箱即用”的特性。对于一个商城系统用户认证、后台管理、表单处理、数据库ORM都是刚需Django内置的这些组件成熟稳定能让我们把精力集中在业务逻辑而非基础设施上。后端框架自然是Django版本锁定在3.2 LTS这是一个长期支持版本在稳定性和社区支持上找到了很好的平衡点。数据库选择了MySQL 5.7/8.0考虑到商城业务涉及较多的事务和关联查询关系型数据库依然是可靠的选择。前端没有采用前后端分离的复杂架构而是使用了Django原生的模板引擎Django Templates配合Bootstrap 5来构建页面。这种选择对于中小型、以内容展示和表单交互为主的商城项目来说开发效率极高避免了分离部署、接口联调等额外复杂度。静态资源使用Whitenoise中间件在本地和生产环境提供高效服务。项目结构清晰遵循了Django的最佳实践。根目录下除了标准的manage.py和配置文件主要应用App按功能模块划分users: 处理用户注册、登录、个人中心、收货地址管理。goods: 核心的商品模块包括商品分类、品牌、SPU标准产品单元、SKU库存量单位模型以及商品列表、详情页的展示逻辑。orders: 订单模块涵盖购物车、订单创建、状态流转、支付回调集成模拟支付和订单管理。payments: 支付模块抽象了支付网关接口目前实现了支付宝沙箱和微信支付模拟接口便于理解支付流程。utils: 存放公共工具函数如自定义的装饰器、验证码生成、短信发送模拟客户端等。2.2 核心数据模型设计解析数据模型是任何应用的基石商城系统的模型设计尤其关键。在这个项目中我重点设计了几个核心模型并充分考虑了扩展性。首先是用户模型UserProfile。我没有直接使用Django内置的AbstractUser进行简单扩展而是采用了与内置User模型一对一关联OneToOneField的方式。这样做的好处是既可以利用Django强大的原生认证系统auth模块又可以为商城用户定制大量额外字段如昵称、头像、性别、生日、默认收货地址等而不会污染原始的auth_user表结构。这种设计在需要频繁升级Django版本或与其他使用标准用户模型的App集成时灵活性更高。商品模型的设计是另一个重点采用了电商领域常见的SPUSKU模式。GoodsSPU表定义了一个标准产品的抽象信息如商品名称、副标题、商品描述、所属分类和品牌。GoodsSKU表则定义了具体的销售属性如颜色、尺寸、规格以及独立的价格、库存、销量和上下架状态。一个SPU对应多个SKU。这种设计将商品的基本信息与销售属性解耦既能高效管理商品公共信息又能灵活应对多规格商品的库存和定价。分类GoodsCategory采用了自关联parent_category字段实现无限级分类并通过db_indexTrue为频繁查询的字段建立索引。订单模型OrderInfo和订单商品模型OrderGoods构成了订单系统的核心。OrderInfo记录了订单的宏观信息订单号唯一、用户、总金额、支付方式、订单状态使用choices选项定义如“待支付”、“待发货”、“待收货”、“已完成”、“已取消”、收货地址快照等。OrderGoods则是一个关联表记录了订单中每个SKU商品的购买数量、成交单价下单时快照与商品实时价格解耦和评价状态。这种设计确保了订单数据的不可变性即使用户后来修改了收货地址或商品价格发生了变化历史订单信息依然保持不变。注意在模型字段设计时对于金额类字段如商品价格、订单总价务必使用DecimalField并指定精确的max_digits总位数和decimal_places小数位数例如max_digits10, decimal_places2。绝对不要使用FloatField因为浮点数在计算和存储时可能存在精度丢失问题这在金融相关的业务中是致命的。3. 核心功能模块的详细实现与实操要点3.1 用户系统从注册登录到个人中心用户模块是流量的入口。注册功能除了常规的用户名、密码、手机号验证我还集成了图形验证码和短信验证码模拟来防止恶意注册。验证码的生成使用Pillow库绘制并将验证码文本存入Redis或Session中用于校验。短信服务则对接了一个模拟接口在实际部署时可以轻松替换为阿里云、腾讯云等提供的短信服务SDK。登录功能直接使用了Django内置的authenticate()和login()函数安全可靠。但有一个关键细节在登录视图View中我不仅校验用户名密码还检查了用户是否被激活is_active以及是否被后台管理员禁用。这为后续可能需要的用户管理提供了钩子。登录成功后使用Django的login_required装饰器来保护需要登录才能访问的视图例如个人中心、收货地址管理页面。个人中心页面展示了用户的基本信息、订单概览和收货地址列表。收货地址管理实现了增删改查全套操作并允许用户设置一个默认地址。在创建或编辑地址时前端通过三级联动选择省市区这里我预先将全国行政区划数据导入到了一个单独的Area模型中通过Ajax异步加载实现无刷新联动提升了用户体验。3.2 商品展示系统列表、详情与搜索商品列表页是商城的门面。视图View中我首先处理了查询参数分类ID、排序方式按价格、销量、上新、页码。通过Django ORM的select_related和prefetch_related方法我有效地避免了在模板中渲染商品时因外键关联而产生的“N1查询问题”。例如在获取商品列表时一次性通过select_related(category, spu)将分类和SPU信息关联查询出来而不是在循环中逐条查询。商品详情页除了展示SKU的详细信息、图片轮播、规格参数外最关键的是库存判断。当用户选择不同规格如颜色、尺寸时前端通过Ajax请求后端后端根据SKU ID实时查询库存并返回。库存数量是电商系统的生命线所有涉及库存增减的操作如下单、取消订单、后台修改都必须放在数据库事务中处理并使用F()表达式进行原子操作防止超卖。例如在用户下单时from django.db import transaction, models with transaction.atomic(): # 1. 创建订单保存点 sid transaction.savepoint() try: # 2. 查询SKU并判断库存使用select_for_update加行锁防止并发修改 sku GoodsSKU.objects.select_for_update().get(idsku_id, is_launchedTrue) if sku.stock buy_count: transaction.savepoint_rollback(sid) return JsonResponse({code: 400, errmsg: 库存不足}) # 3. 使用F表达式原子更新库存和销量 GoodsSKU.objects.filter(idsku_id).update( stockmodels.F(stock) - buy_count, salesmodels.F(sales) buy_count ) # 4. 创建订单记录... transaction.savepoint_commit(sid) except Exception as e: transaction.savepoint_rollback(sid) # 记录日志并返回错误搜索功能基于Django的Q对象实现简单的多条件过滤。对于更复杂的全文搜索需求项目预留了接口可以方便地集成像django-haystackWhoosh或Elasticsearch这样的专业搜索引擎。3.3 购物车与订单流程的完整实现购物车设计采用了混合方案用户未登录时购物车数据存储在浏览器的localStorage中用户登录后则同步到服务器端的数据库Cart表中。这样做既保证了未登录用户的体验又实现了登录后数据的持久化和多端同步。购物车表Cart很简单主要字段是用户、SKU、商品数量和添加时间。订单流程是电商最核心、最复杂的链路我将其拆解为几个清晰的步骤并在视图函数中严格校验每一步订单确认页用户从购物车选择商品进入。视图需要校验所选SKU是否有效、库存是否充足、用户是否有默认收货地址。这里会计算商品总价、运费生成一个订单总金额的预览。所有价格信息都是从数据库实时查询并计算的确保准确性。订单创建用户提交订单。这是整个系统里对数据一致性和事务性要求最高的地方。我使用了Django的transaction.atomic()装饰器来确保以下操作在一个数据库事务中完成从购物车中取出选中的商品。遍历每个商品使用select_for_update()锁定SKU行再次检查库存。使用F()表达式原子性地减少库存、增加销量。生成唯一的订单号采用“时间戳用户ID随机数”的算法。创建OrderInfo主订单记录和多个OrderGoods子订单记录。将购物车中对应的商品项删除。 任何一步失败整个事务都会回滚库存和销量数据保持不变保证了数据的强一致性。订单支付订单创建成功后跳转到支付选择页。项目集成了支付宝和微信支付的模拟流程。以支付宝为例视图会调用支付宝提供的Python SDK生成一个包含订单号、金额、商品描述等信息的支付请求参数前端使用这些参数跳转到支付宝的支付页面或唤起手机支付宝App。支付成功后支付宝会异步通知回调我们指定的一个后端接口/payments/alipay/notify/。这个回调接口的处理至关重要必须验证支付宝传来的签名确保通知的真实性然后根据通知中的订单号更新本地订单状态为“已支付”最后返回一个success字符串给支付宝否则支付宝会认为通知失败而反复重试。订单状态管理用户可以在个人中心查看订单列表和详情。后台管理员则可以通过Django Admin或自定义的管理后台操作订单状态发货、完成、取消等。每次状态变更都应记录日志并可以考虑通过消息队列异步发送通知如短信、邮件给用户。实操心得在开发支付回调接口时一定要做好日志记录将支付宝/微信支付回调过来的所有参数无论是成功还是失败都详细记录下来。因为支付环境复杂网络抖动、用户中途关闭页面等都可能导致问题。有了完整的日志当用户投诉“付了款但订单没更新”时你才能快速定位是支付平台的通知没发出来还是我们的接口处理失败了。此外回调接口的代码必须做幂等处理即同一条支付成功的通知即使因为网络原因被重复调用多次最终结果也应该是订单只被标记为支付成功一次避免重复给用户加积分或发货。4. 后台管理系统的快速搭建与深度定制Django Admin是这个项目的一大亮点它几乎零代码就为我们生成了一个功能强大的商品和订单管理后台。但默认的Admin往往不能满足实际业务需求需要进行深度定制。4.1 基础模型注册与列表优化首先在各自App的admin.py文件中使用admin.site.register(YourModel)进行注册。但很快你会发现默认的列表页只显示对象的字符串表示信息量很少。这时可以通过定义ModelAdmin类来定制from django.contrib import admin from .models import GoodsSKU admin.register(GoodsSKU) class GoodsSKUAdmin(admin.ModelAdmin): # 列表页显示的字段 list_display [id, name, spu, category, price, stock, sales, is_launched] # 支持直接编辑的字段无需进入详情页 list_editable [price, stock, is_launched] # 右侧过滤器 list_filter [category, is_launched, create_time] # 搜索框支持的字段 search_fields [name, spu__name, id] # 每页显示数量 list_per_page 50这样管理员就能在一个页面里快速浏览、搜索、筛选和编辑大量商品SKU了。4.2 复杂表单与内联编辑对于商品SPUGoodsSPU它下面有多个SKU我们希望在编辑SPU的同时能直接编辑或新增其关联的SKU。这就要用到TabularInline或StackedInline。class GoodsSKUInline(admin.TabularInline): model GoodsSKU extra 1 # 默认显示一个空白的SKU表单 fields [name, price, stock, sales, spec] admin.register(GoodsSPU) class GoodsSPUAdmin(admin.ModelAdmin): inlines [GoodsSKUInline] # ... 其他配置现在在SPU的编辑页面下方会以一个表格的形式列出所有关联的SKU并可以直接修改或新增管理效率大大提升。4.3 自定义Action与批量操作后台经常需要执行批量操作比如将选中的商品批量上架或下架。Django Admin可以很方便地定义自定义Action。def make_launched(modeladmin, request, queryset): queryset.update(is_launchedTrue) make_launched.short_description 批量上架选中的商品 def make_unlaunched(modeladmin, request, queryset): queryset.update(is_launchedFalse) make_unlaunched.short_description 批量下架选中的商品 class GoodsSKUAdmin(admin.ModelAdmin): actions [make_launched, make_unlaunched] # ... 其他配置这样管理员在商品列表页勾选多个商品后就可以从Action下拉菜单中执行批量操作。4.4 字段重写与富文本编辑器集成商品描述通常需要富文本编辑。Django Admin默认是普通文本框我们可以集成第三方编辑器比如django-ckeditor。安装配置后只需在ModelAdmin中重写对应字段的form即可from django import forms from ckeditor.widgets import CKEditorWidget class GoodsSPUAdminForm(forms.ModelForm): description forms.CharField(widgetCKEditorWidget()) class Meta: model GoodsSPU fields __all__ class GoodsSPUAdmin(admin.ModelAdmin): form GoodsSPUAdminForm现在SPU的描述字段就变成了一个功能强大的富文本编辑器。5. 项目部署、性能优化与安全加固实录5.1 从开发到生产关键配置迁移开发时我们使用Django自带的开发服务器和SQLite但生产环境完全不同。首先在settings.py中通过环境变量区分不同配置。关键改动包括数据库切换到MySQL或PostgreSQL配置连接池如使用django-db-connections。密钥与调试SECRET_KEY必须从环境变量读取绝对不能硬编码在代码中。DEBUG必须设置为False。静态文件使用python manage.py collectstatic收集所有静态文件到指定目录如/static/然后通过Nginx直接代理或者使用白名单中间件Whitenoise对于中小流量项目足够。Allowed Hosts必须设置ALLOWED_HOSTS [你的域名, 你的服务器IP]否则Django会拒绝服务。中间件生产环境需要添加安全相关的中间件如SecurityMiddleware自动添加安全头部、SessionMiddleware配置为使用数据库或Redis缓存存储Session。5.2 性能优化实战技巧随着商品和用户量增长性能瓶颈会逐渐暴露。以下是我在实践中总结的几个优化点数据库查询优化这是最常见的瓶颈。持续使用django-debug-toolbar监控页面产生的SQL查询。坚决杜绝N1查询善用select_related用于一对一、多对一正向关联和prefetch_related用于多对多、一对多反向关联。对于复杂的聚合查询考虑使用annotate和aggregate在数据库层面完成计算。缓存策略Django提供了强大的缓存框架。我将以下内容纳入了缓存全站缓存对于变化不频繁的页面如商品详情页在商品信息更新时手动清除缓存可以使用CacheMiddleware进行全页面缓存。片段缓存在模板中使用{% cache 300 sidebar %}...{% endcache %}缓存页面中某个部分如商品分类导航栏。数据缓存使用from django.core.cache import cacheAPI缓存昂贵的查询结果如首页的热销商品排行榜。缓存后端可以配置为Redis或Memcached。静态文件与媒体文件务必使用CDN分发静态文件CSS, JS, 图片。用户上传的媒体文件商品图、用户头像建议存储到对象存储服务如阿里云OSS、腾讯云COS它们带宽大、成本低、有图片处理能力缩略图、水印。5.3 安全加固清单安全无小事尤其是涉及支付和用户数据的商城系统。CSRF保护Django默认已开启确保所有POST表单都包含{% csrf_token %}。XSS防护Django模板默认自动转义HTML标签。但如果某些字段需要富文本在渲染时必须使用|safe过滤器并确保输入时已经过清洗如使用bleach库。SQL注入坚持使用Django ORM或参数化查询基本可以免疫。敏感信息密码必须使用make_password哈希存储绝对禁止明文。数据库连接密码、第三方API密钥等必须通过环境变量配置。文件上传限制上传文件的类型通过MIME类型和后缀名双重校验、大小并对图片进行重命名如使用UUID防止用户上传恶意文件或通过路径遍历攻击服务器。权限控制除了前端的登录检查后端每个视图函数都要进行权限校验。使用login_required、permission_required装饰器或自定义装饰器检查用户角色。5.4 常见问题与排查技巧实录在开发和维护这个项目的过程中我踩过不少坑也总结了一些排查问题的经验。问题一静态文件在开发环境正常部署后404。排查首先检查settings.py中的STATIC_URL和STATIC_ROOT配置。STATIC_ROOT是执行collectstatic后文件收集的目录需要确保Nginx或Apache的配置正确指向了这个目录或者STATICFILES_DIRS配置正确。使用python manage.py findstatic css/style.css命令可以查找Django认为的静态文件路径。解决对于使用Nginx的情况在配置文件中添加一个location块location /static/ { alias /path/to/your/static_root/; }。确保Nginx用户对该目录有读取权限。问题二使用F()表达式更新后从数据库重新取出的值好像没变排查这是一个常见的误解。F()表达式更新是在数据库层面进行的原子操作但更新后当前Python内存中的模型实例对象obj的字段值并不会自动刷新。解决如果需要获取更新后的值必须从数据库重新加载该对象obj.refresh_from_db()。问题三支付回调接口被重复调用导致订单状态异常更新。排查检查支付回调接口的日志看是否收到了多条内容相同的POST请求。这通常是支付平台的网络重试机制导致的。解决实现接口的幂等性。在回调处理逻辑的最开始根据支付平台传过来的唯一交易号如支付宝的trade_no去查询本地是否已存在处理成功的记录。如果已存在直接返回成功响应不再执行后续的订单更新逻辑。可以在数据库中为这个交易号建立唯一索引从数据库层面防止重复记录。问题四后台Admin操作速度很慢特别是有关联数据的列表页。排查使用django-debug-toolbar查看该Admin页面生成的SQL很可能是因为在列表页显示外键字段如list_display [spu]时每条记录都去单独查询了一次关联表。解决在自定义的ModelAdmin中重写get_queryset方法使用select_related提前加载关联数据def get_queryset(self, request): return super().get_queryset(request).select_related(spu, category)。这个Django商城项目源码就像一本涵盖了需求分析、设计、编码、调试和部署思考的实战笔记。它可能没有用到最前沿的微服务或云原生架构但其中对业务逻辑的梳理、对数据一致性的处理、对常见问题的规避方案都是构建一个可靠Web应用的通用经验。代码是死的但解决问题的思路是活的。希望你在阅读和运行这份代码时能更关注“为什么这么设计”而不仅仅是“怎么实现”。当你理解了背后的权衡与考量也就具备了独立设计和开发更复杂系统的能力。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进