Django电商网站开发实战:从模型设计到并发控制

发布时间:2026/9/2 6:21:15
Django电商网站开发实战:从模型设计到并发控制 简介本资源是一套完整的基于Django框架开发的电商网站毕设/课设项目面向计算机、电子信息工程等专业本科生解决Web全栈开发实践能力培养与课程设计选题落地难题。压缩包共1794个文件涵盖137个核心Python后端逻辑文件含Model/View/URL/Forms配置、1075个JS交互脚本、139个CSS样式文件及130余张PNG/GIF/JPG静态资源完整支撑MTV架构下的前后端协同开发整体包体仅5.86MB轻量易部署。已有31人学习下载。项目内置可运行的数据库迁移脚本、集成支付宝/微信支付模拟逻辑、用户认证与购物车全流程代码并包含Bootstrap前端组件库如bootstrap.min.css、editor.css等与响应式页面模板开箱即用便于快速理解Django ORM建模、表单验证、安全防护防XSS/SQL注入及支付流程闭环设计。1. 项目缘起与核心价值为什么是Django电商又到了一年一度的毕业季和课程设计季后台私信里关于“毕设/课设选题”的咨询又多了起来。其中“做一个电商网站”是出现频率最高的需求之一。这很好理解电商系统业务逻辑清晰、功能模块典型既能展示你的全栈能力又有一个看得见摸得着的成果。但随之而来的问题是技术栈怎么选后台用Java的Spring Boot还是PHP的Laravel或是Node.js的Express我的建议是如果你的主力语言是Python或者你想快速上手、把精力更多放在业务逻辑而非框架配置上那么Django几乎是这个场景下的不二之选。很多人会问Django在国内使用广泛吗答案是肯定的。虽然不如Java生态在大型企业级应用中那么根深蒂固但Django凭借其“开箱即用”的特性在快速开发、创业公司、数据驱动型应用以及高校教学和实践中占据了非常重要的地位。从知乎、豆瓣早年的架构到如今众多中小型互联网公司的后台都能看到Django的身影。它不是一个“玩具”框架而是一个经过时间检验、功能完备的“重武器”。对于毕设或课设而言选择Django构建电商网站核心价值在于**“高完成度”和“深度可扩展性”**。你不需要从零开始造轮子去处理用户认证、后台管理、数据库ORM这些繁琐但必需的基础设施。Django自带的后台管理Admin能让你在几分钟内拥有一个功能强大的商品、订单、用户管理界面这为项目演示加分不少。同时Django严格的MTVModel-Template-View模式能强迫你写出结构清晰的代码这对于向答辩老师展示你的软件工程素养至关重要。2. 项目蓝图一个电商网站的核心模块拆解在动手写代码之前我们必须先想清楚一个最小可用的电商网站应该包含哪些部分。盲目开始很容易陷入细节最后做出一个“四不像”。基于Django我们可以将项目清晰地划分为以下几个核心应用App每个应用负责一块独立的业务功能。2.1 用户中心accounts/user这是所有系统的基石。Django自带了强大的django.contrib.auth模块但我们通常需要扩展它。核心模型继承AbstractUser或AbstractBaseUser创建自定义用户模型。务必在项目一开始就做这件事因为一旦数据库迁移migrate执行后再修改用户模型会非常麻烦。我们需要添加的字段可能包括手机号、头像、默认收货地址等。功能视图注册含邮箱/手机验证码、登录、登出、个人信息查看与修改、密码重置。这里会用到Django的类视图如LoginView,LogoutView和表单Form。关键技巧使用django-allauth这个第三方库可以极大地简化社交登录微信、微博、QQ和邮箱验证流程但作为毕设我建议先手写核心流程以加深理解。2.2 商品中心goods/product电商的核心是商品。模型设计这是体现你数据库设计能力的地方。至少需要Category商品分类和Product商品SPU两个模型。更完善的設計会引入ProductSKU库存量单位用于管理不同规格如颜色、尺寸商品的价格和库存。这里涉及到一对多一个分类下有多个商品和多对多商品关联多个属性的关系。数据展示商品列表页支持按分类、价格、销量排序和筛选、商品详情页。列表页的分页Django内置Paginator和详情页的图片画廊是需要仔细处理的地方。后台管理利用Django Admin你可以通过简单的配置为商品模型提供一个功能强大的增删改查界面。通过自定义ModelAdmin类你甚至可以实现在列表页直接修改库存。2.3 购物车与订单cart/order这是电商业务逻辑最复杂的部分。购物车设计有两种常见实现方式。对于未登录用户可以将购物车数据存储在浏览器的session中对于已登录用户则存入数据库的Cart模型。模型需要关联用户和商品SKU并记录数量。订单流程这是重中之重。流程通常为从购物车跳转到订单确认页 - 生成待付款订单Order及订单项OrderItem - 用户选择支付方式 - 跳转支付或模拟支付 - 支付成功回调更新订单状态 - 用户查看订单列表和详情。状态机思维订单模型一定要有一个status字段并使用选择项如‘unpaid’,‘paid’,‘shipped’,‘received’,‘canceled’。所有对订单的操作支付、发货、确认收货都应是对状态的谨慎变更并在变更前后进行逻辑检查如只有“已支付”的订单才能发货。2.4 支付与通知payment对于毕设通常不需要接入真实的微信或支付宝支付但模拟一个完整的支付流程是必须的。模拟支付创建一个支付视图接收订单号展示一个模拟的支付页面。点击“确认支付”后通过一个异步任务Celery或直接调用一个函数模拟支付平台回调你的“支付成功通知接口”。回调接口这个接口需要验证“回调请求”的合法性虽然模拟时很简单然后更新对应订单的状态为“已支付”并可能触发“发送订单邮件通知”等后续操作。经验之谈即使模拟也要把回调接口设计成幂等的即多次收到同一支付成功的回调结果应该一致这是线上系统的基本要求。3. 从零到一Django项目初始化与环境搭建现在让我们打开终端开始真正的构建。我假设你已经在电脑上安装好了Python3和pip。3.1 创建虚拟环境与安装Django永远不要在系统全局Python环境里直接安装项目依赖。# 创建项目目录并进入 mkdir django_ecommerce cd django_ecommerce # 创建虚拟环境推荐使用venv python3 -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate # 安装Django和常用依赖 pip install django pillowpillow是Python的图像处理库Django的ImageField字段需要它来工作。3.2 创建项目与应用AppDjango有“项目”和“应用”的概念。一个项目是网站的配置集合应用是具体的功能模块。# 创建名为 config 的Django项目也可以用 . 直接创建在当前目录但结构更清晰 django-admin startproject config . # 创建我们规划好的各个应用 python manage.py startapp accounts python manage.py startapp goods python manage.py startapp cart python manage.py startapp order python manage.py startapp payment创建后你的目录结构应该类似这样django_ecommerce/ ├── venv/ ├── manage.py ├── config/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── accounts/ ├── goods/ ├── cart/ ├── order/ └── payment/3.3 配置项目设置settings.py这是Django项目的心脏大部分问题都出在这里的配置不当。注册应用在config/settings.py的INSTALLED_APPS列表末尾添加我们创建的应用和Django内置的常用应用。INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, # 自定义应用 accounts.apps.AccountsConfig, goods.apps.GoodsConfig, cart.apps.CartConfig, order.apps.OrderConfig, payment.apps.PaymentConfig, ]数据库默认使用SQLite对于毕设完全够用。如果想用MySQL或PostgreSQL需要修改DATABASES配置并安装对应的数据库驱动如pip install mysqlclient。静态文件与媒体文件# 文件末尾添加 STATIC_URL /static/ STATICFILES_DIRS [BASE_DIR / static] # 开发阶段存放静态文件的目录 STATIC_ROOT BASE_DIR / staticfiles # 生产环境收集静态文件的目录 MEDIA_URL /media/ MEDIA_ROOT BASE_DIR / media # 用户上传文件如图片的存放目录模板路径确保TEMPLATES中的DIRS包含项目根目录的templates文件夹os.path.join(BASE_DIR, templates)。语言与时区LANGUAGE_CODE ‘zh-hans’TIME_ZONE ‘Asia/Shanghai’。3.4 定义第一个模型自定义用户模型正如之前强调的这是首先要做的事。在accounts/models.py中from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): # 添加自定义字段 phone models.CharField(verbose_name手机号, max_length11, blankTrue, nullTrue) avatar models.ImageField(verbose_name头像, upload_toavatars/, blankTrue, nullTrue) # upload_to 指定了图片上传到 media/avatars/ 目录下 class Meta: db_table auth_user # 可以指定表名保持和默认一致或自定义 verbose_name 用户 verbose_name_plural verbose_name def __str__(self): return self.username然后在config/settings.py中告诉Django使用我们的自定义用户模型AUTH_USER_MODEL accounts.User最后生成并应用数据库迁移python manage.py makemigrations python manage.py migrate踩坑提示如果在执行migrate之后才修改AUTH_USER_MODEL你会遇到依赖冲突。正确做法是在执行第一次migrate创建初始表之前就设置好它。如果项目已经初始化可能需要清空数据库删除db.sqlite3文件并重新迁移。4. 深入业务逻辑以商品与购物车为例的实战编码环境搭好基础已定我们来攻克两个核心业务模块。4.1 商品模型的进阶设计在goods/models.py中我们来设计一个支持多规格的商品模型。from django.db import models class Category(models.Model): 商品分类 name models.CharField(verbose_name分类名, max_length50) parent models.ForeignKey(self, verbose_name父分类, on_deletemodels.CASCADE, nullTrue, blankTrue, related_namechildren) is_nav models.BooleanField(verbose_name是否显示在导航栏, defaultFalse) sort_order models.IntegerField(verbose_name排序, default0) class Meta: verbose_name 商品分类 verbose_name_plural verbose_name ordering [sort_order, id] def __str__(self): return self.name class Product(models.Model): 商品SPU标准产品单元 name models.CharField(verbose_name商品名称, max_length200) category models.ForeignKey(Category, verbose_name所属分类, on_deletemodels.PROTECT, related_nameproducts) main_image models.ImageField(verbose_name主图, upload_toproducts/main/) desc models.TextField(verbose_name商品描述, blankTrue) is_on_sale models.BooleanField(verbose_name是否上架, defaultTrue) created_at models.DateTimeField(verbose_name创建时间, auto_now_addTrue) updated_at models.DateTimeField(verbose_name更新时间, auto_nowTrue) class Meta: verbose_name 商品 verbose_name_plural verbose_name ordering [-created_at] def __str__(self): return self.name class ProductSKU(models.Model): 商品SKU库存量单位 product models.ForeignKey(Product, verbose_name所属SPU, on_deletemodels.CASCADE, related_nameskus) sku_code models.CharField(verbose_nameSKU编码, max_length50, uniqueTrue) price models.DecimalField(verbose_name价格, max_digits10, decimal_places2) market_price models.DecimalField(verbose_name市场价, max_digits10, decimal_places2, nullTrue, blankTrue) stock models.PositiveIntegerField(verbose_name库存, default0) sales models.PositiveIntegerField(verbose_name销量, default0) # 这里可以关联规格属性例如颜色、尺寸为了简化我们用JSON字段存储 specs models.JSONField(verbose_name规格属性, defaultdict) class Meta: verbose_name 商品SKU verbose_name_plural verbose_name def __str__(self): return f{self.product.name} - {self.sku_code}这个设计将商品信息SPU和库存价格信息SKU分离是电商系统的常见做法。specs字段使用JSONFieldDjango 3.1支持灵活地存储规格组合。4.2 购物车的两种状态处理购物车需要同时处理登录和未登录用户这是一个典型的业务场景。我们在cart/models.py中创建数据库购物车模型同时在cart/utils.py中编写处理Session购物车的工具函数。cart/models.py:from django.db import models from accounts.models import User from goods.models import ProductSKU class Cart(models.Model): 登录用户的购物车 user models.ForeignKey(User, verbose_name用户, on_deletemodels.CASCADE, related_namecarts) sku models.ForeignKey(ProductSKU, verbose_name商品SKU, on_deletemodels.CASCADE) quantity models.PositiveIntegerField(verbose_name数量, default1) selected models.BooleanField(verbose_name是否选中, defaultTrue) created_at models.DateTimeField(auto_now_addTrue) class Meta: verbose_name 购物车 verbose_name_plural verbose_name unique_together [user, sku] # 同一个用户同一个SKU只应有一条记录 def __str__(self): return f{self.user.username}s cart item: {self.sku}cart/utils.py:def get_cart_from_session(request): 从session中获取购物车数据格式{sku_id: quantity} cart request.session.get(cart, {}) # 确保cart是一个字典键为字符串因为session序列化 if not isinstance(cart, dict): cart {} request.session[cart] cart return cart def add_to_session_cart(request, sku_id, quantity1): 添加商品到session购物车 cart get_cart_from_session(request) sku_id_str str(sku_id) cart[sku_id_str] cart.get(sku_id_str, 0) quantity request.session[cart] cart request.session.modified True # 标记session已被修改确保保存 def merge_carts(request, user): 用户登录后合并session购物车到数据库购物车 session_cart get_cart_from_session(request) if not session_cart: return from .models import Cart from goods.models import ProductSKU for sku_id_str, quantity in session_cart.items(): try: sku ProductSKU.objects.get(idint(sku_id_str)) except ProductSKU.DoesNotExist: continue # 尝试获取或创建数据库中的购物车项 cart_item, created Cart.objects.get_or_create( useruser, skusku, defaults{quantity: quantity} ) if not created: # 如果已存在则数量累加 cart_item.quantity quantity cart_item.save() # 合并完成后清空session中的购物车 del request.session[cart]cart/views.py中的添加购物车视图示例:from django.contrib.auth.decorators import login_required from django.http import JsonResponse from django.views.decorators.http import require_POST from .utils import add_to_session_cart, merge_carts from .models import Cart from goods.models import ProductSKU require_POST def add_to_cart(request): sku_id request.POST.get(sku_id) quantity int(request.POST.get(quantity, 1)) try: sku ProductSKU.objects.get(idsku_id, product__is_on_saleTrue) except ProductSKU.DoesNotExist: return JsonResponse({code: 1, errmsg: 商品不存在或已下架}) # 检查库存 if sku.stock quantity: return JsonResponse({code: 2, errmsg: 库存不足}) if request.user.is_authenticated: # 已登录用户操作数据库 cart_item, created Cart.objects.get_or_create( userrequest.user, skusku, defaults{quantity: quantity} ) if not created: cart_item.quantity quantity cart_item.save() # 再次检查库存并发情况下 if cart_item.quantity sku.stock: cart_item.quantity sku.stock cart_item.save() return JsonResponse({code: 2, errmsg: 库存不足已调整为最大库存}) else: # 未登录用户操作session add_to_session_cart(request, sku_id, quantity) return JsonResponse({code: 0, msg: 添加成功})这个视图处理了登录/未登录两种状态并进行了库存校验。在用户登录时我们需要在登录视图的响应中调用merge_carts函数实现购物车数据的无缝迁移。5. 订单系统的状态流转与并发控制订单系统是电商的核心其稳定性和正确性至关重要。这里我们重点讨论状态机和库存扣减的并发问题。5.1 订单模型与状态机在order/models.py中from django.db import models from accounts.models import User from goods.models import ProductSKU class Order(models.Model): 订单主表 ORDER_STATUS ( (1, 待支付), (2, 已支付), (3, 已发货), (4, 已完成), (5, 已取消), (6, 售后中), ) order_sn models.CharField(verbose_name订单号, max_length30, uniqueTrue) user models.ForeignKey(User, verbose_name用户, on_deletemodels.PROTECT, related_nameorders) total_amount models.DecimalField(verbose_name订单总金额, max_digits10, decimal_places2) pay_amount models.DecimalField(verbose_name实付金额, max_digits10, decimal_places2) freight models.DecimalField(verbose_name运费, max_digits10, decimal_places2, default0) pay_method models.SmallIntegerField(verbose_name支付方式, choices((1, 支付宝), (2, 微信支付), (3, 模拟支付)), default3) status models.SmallIntegerField(verbose_name订单状态, choicesORDER_STATUS, default1) remarks models.TextField(verbose_name订单备注, blankTrue) created_at models.DateTimeField(verbose_name创建时间, auto_now_addTrue) paid_at models.DateTimeField(verbose_name支付时间, nullTrue, blankTrue) class Meta: verbose_name 订单 verbose_name_plural verbose_name ordering [-created_at] def __str__(self): return self.order_sn def generate_order_sn(self): 生成唯一订单号时间用户ID随机数 from datetime import datetime import random return datetime.now().strftime(%Y%m%d%H%M%S) str(self.user.id).zfill(4) str(random.randint(10, 99)) def save(self, *args, **kwargs): if not self.order_sn: self.order_sn self.generate_order_sn() super().save(*args, **kwargs) class OrderItem(models.Model): 订单商品项 order models.ForeignKey(Order, verbose_name所属订单, on_deletemodels.CASCADE, related_nameitems) sku models.ForeignKey(ProductSKU, verbose_name商品SKU, on_deletemodels.PROTECT) price models.DecimalField(verbose_name单价, max_digits10, decimal_places2) quantity models.PositiveIntegerField(verbose_name数量, default1) # 快照信息保存下单时的商品信息防止后续商品信息变更 snapshot models.JSONField(verbose_name商品快照, defaultdict) class Meta: verbose_name 订单商品项 verbose_name_plural verbose_name def __str__(self): return f{self.order.order_sn} - {self.sku.product.name}注意几个关键点order_sn使用自定义生成逻辑确保唯一性比单纯的自增ID更安全避免被爬取订单数量。status使用选择字段定义状态这是状态机的核心。OrderItem.snapshot这是一个非常重要的设计。下单时将商品名称、图片、规格等关键信息以JSON格式存入。这样即使后台商品信息后续被修改或删除订单历史记录依然完整。这是电商系统的标配。5.2 下单与支付库存扣减的并发陷阱用户点击“提交订单”时我们需要做两件原子性操作创建订单和扣减库存。在高并发场景下这里是个大坑。错误示范会产生超卖# views.py 中一个危险的下单函数片段 def create_order(request): # ... 获取购物车选中商品 ... for cart_item in cart_items: sku cart_item.sku if sku.stock cart_item.quantity: return error_response(库存不足) # 问题点判断库存和扣减库存不是原子操作 sku.stock - cart_item.quantity sku.save() # 多个请求可能同时执行到这里导致stock被错误覆盖 # ... 创建订单 ...当两个用户同时购买最后一件商品时他们可能都通过了if sku.stock cart_item.quantity的判断然后都执行了扣减导致库存变成负数超卖。解决方案使用数据库的乐观锁或悲观锁。方案一使用Django的F表达式 update推荐乐观锁from django.db.models import F from django.db import transaction def deduct_stock(sku_id, quantity): 扣减库存使用F表达式避免竞态条件 affected_rows ProductSKU.objects.filter( idsku_id, stock__gtequantity # 在更新时再次检查库存 ).update(stockF(stock) - quantity) return affected_rows 0 # 返回是否更新成功 transaction.atomic def create_order(request): user request.user # ... 获取购物车选中商品计算总价等 ... # 1. 先生成订单号等基本信息保存订单状态为待支付 order Order.objects.create(useruser, total_amounttotal, pay_amounttotal, status1) # 2. 逐个扣减库存并创建订单项 for cart_item in cart_items: sku cart_item.sku # 使用原子操作扣减库存 if not deduct_stock(sku.id, cart_item.quantity): # 如果扣减失败说明库存不足需要回滚整个事务 transaction.set_rollback(True) # 手动触发回滚 return JsonResponse({code: 1, errmsg: f商品{sku.product.name}库存不足请重新下单}) # 创建订单项保存快照 OrderItem.objects.create( orderorder, skusku, pricesku.price, quantitycart_item.quantity, snapshot{ name: sku.product.name, image: sku.product.main_image.url if sku.product.main_image else , specs: sku.specs, sku_code: sku.sku_code, } ) # 3. 删除购物车中对应的项 cart_item.delete() # 4. 所有操作成功返回订单信息 return JsonResponse({code: 0, order_sn: order.order_sn})这里的关键是deduct_stock函数和transaction.atomic装饰器。F(stock) - quantity让数据库在原子操作中完成计算避免了从Python读取-计算-写回的非原子过程。filter(stock__gtequantity)在更新时再次作为条件如果库存不足则update语句影响的行数为0函数返回False。transaction.atomic确保整个下单过程是一个数据库事务。只要任何一个商品库存扣减失败就会触发回滚订单不会被创建之前扣减的库存也会恢复因为update语句根本没执行成功。这保证了数据的一致性。方案二使用select_for_update悲观锁对于极端高并发场景可以使用数据库的行级锁。from django.db import transaction transaction.atomic def create_order_pessimistic(request): # ... sku ProductSKU.objects.select_for_update().get(idsku_id) # 这会锁定该行记录直到事务结束 if sku.stock quantity: transaction.set_rollback(True) return error_response(库存不足) sku.stock - quantity sku.save() # ...select_for_update在事务中锁定查询到的行其他尝试修改这些行的事务会被阻塞。这能保证绝对的一致性但会严重影响并发性能。对于毕设和绝大多数场景方案一的乐观锁足够且更优。6. 前端交互与项目部署收尾一个完整的项目离不开用户界面和最终的部署展示。6.1 模板渲染与静态文件Django使用模板系统来渲染HTML。我们可以在每个应用的目录下创建templates文件夹也可以集中在项目根目录的templates下按应用名分子目录。基础模板在templates/base.html中定义整个网站的基本骨架导航栏、页脚、引入CSS/JS。!DOCTYPE html html langzh-CN head meta charsetUTF-8 title{% block title %}我的电商网站{% endblock %}/title link relstylesheet href{% static css/bootstrap.min.css %} {% block extra_css %}{% endblock %} /head body {% include ‘_navbar.html’ %} !-- 引入导航栏组件 -- div classcontainer mt-4 {% block content %}{% endblock %} /div {% include ‘_footer.html’ %} !-- 引入页脚组件 -- script src{% static js/jquery.min.js %}/script script src{% static js/bootstrap.bundle.min.js %}/script {% block extra_js %}{% endblock %} /body /html页面模板在其他模板中继承它例如goods/product_list.html{% extends ‘base.html’ %} {% load static %} {% block title %}商品列表{% endblock %} {% block content %} h2商品列表/h2 div classrow {% for product in product_list %} div classcol-md-4 mb-4 div classcard img src{{ product.main_image.url }} classcard-img-top alt{{ product.name }} div classcard-body h5 classcard-title{{ product.name }}/h5 p classcard-text价格: ¥{{ product.min_price }}/p a href{% url goods:product_detail product.id %} classbtn btn-primary查看详情/a /div /div /div {% empty %} p暂无商品。/p {% endfor %} /div {% endblock %}静态文件将Bootstrap、jQuery等CSS/JS文件放在static/目录下。使用{% static ‘path/to/file’ %}模板标签引用它们。开发时Django的runserver会自动处理静态文件。上线前需要运行python manage.py collectstatic收集所有静态文件到STATIC_ROOT。6.2 使用Django REST Framework构建API可选但推荐如果你的毕设要求前后端分离或者你想让项目看起来更“现代”那么集成Django REST Framework (DRF) 是个绝佳选择。它能让你的Django项目快速提供RESTful API。安装pip install djangorestframework注册应用在settings.py的INSTALLED_APPS中添加‘rest_framework’。创建序列化器在goods/serializers.py中定义如何将Product模型转换为JSON。from rest_framework import serializers from .models import Product, ProductSKU class ProductSKUSerializer(serializers.ModelSerializer): class Meta: model ProductSKU fields [‘id’, ‘sku_code’, ‘price’, ‘market_price’, ‘stock’, ‘specs’] class ProductSerializer(serializers.ModelSerializer): skus ProductSKUSerializer(manyTrue, read_onlyTrue) # 嵌套序列化SKU min_price serializers.SerializerMethodField() class Meta: model Product fields [‘id’, ‘name’, ‘category’, ‘main_image’, ‘desc’, ‘is_on_sale’, ‘skus’, ‘min_price’] def get_min_price(self, obj): # 计算商品的最低价格 skus obj.skus.filter(stock__gt0) return min([sku.price for sku in skus]) if skus else 0创建视图集在goods/views.py中使用视图集可以极简地生成CRUD API。from rest_framework import viewsets from .models import Product from .serializers import ProductSerializer class ProductViewSet(viewsets.ReadOnlyModelViewSet): 商品视图集只提供读操作列表和详情 queryset Product.objects.filter(is_on_saleTrue).prefetch_related(‘skus’) serializer_class ProductSerializer # 可以在这里添加过滤、搜索、排序等配置配置路由在项目urls.py中使用DRF的DefaultRouter自动生成API路由。from django.contrib import admin from django.urls import path, include from rest_framework.routers import DefaultRouter from goods.views import ProductViewSet router DefaultRouter() router.register(r‘products’, ProductViewSet) urlpatterns [ path(‘admin/’, admin.site.urls), path(‘api/’, include(router.urls)), # ... 你的其他URL配置 ... ]现在访问/api/products/就能获取商品列表的JSON数据访问/api/products/1/就能获取id为1的商品详情。前端如Vue.js, React可以轻松消费这些API。6.3 部署上线让导师和同学访问你的作品本地运行python manage.py runserver只能你自己访问。要让别人也能看你需要部署。对于毕设演示最简单的方式是使用PythonAnywhere或Heroku这类PaaS平台。这里简述PythonAnywhere的步骤注册PythonAnywhere账号有免费档位。在Dashboard中创建一个新的Web App选择“Manual configuration” - 选择你的Python版本。通过Bash控制台克隆你的代码仓库或上传代码zip包。创建虚拟环境并安装依赖pip install -r requirements.txt你需要先在本地的项目根目录生成requirements.txt文件pip freeze requirements.txt。配置静态文件和媒体文件在Web App的配置页面分别设置Static files的URL和Directory指向你的staticfiles和media目录。修改设置在PythonAnywhere的Bash中修改settings.py设置DEBUG FalseALLOWED_HOSTS [‘你的用户名.pythonanywhere.com’]并配置数据库可以使用PythonAnywhere提供的MySQL或继续用SQLite。运行迁移和收集静态文件python manage.py migrate python manage.py collectstatic重新加载你的Web App。现在你的Django电商网站就可以通过https://你的用户名.pythonanywhere.com被访问了。我个人在部署时最常遇到的坑是静态文件404。务必确保STATIC_ROOT设置正确并且collectstatic命令成功运行同时在PythonAnywhere的Web配置中正确映射了静态文件路径。另一个坑是ALLOWED_HOSTS在生产环境必须设置否则Django会拒绝服务。7. 项目优化与扩展思路完成基础功能后如果你想在答辩中脱颖而出可以考虑加入以下一两个亮点功能这能显著提升项目的深度和复杂度。7.1 集成全文搜索引擎商品列表的简单过滤如通过分类ID性能尚可但一旦需要复杂的搜索如按商品名称、描述模糊匹配数据库的LIKE查询就会成为性能瓶颈。集成Elasticsearch或Django-Haystack后端支持Whoosh、Elasticsearch等可以解决这个问题。基本思路商品上架/更新时将其标题、描述、分类等信息索引到搜索引擎。用户搜索时请求被发送到搜索引擎返回匹配的商品ID列表再用这些ID去数据库查询完整的商品信息。虽然增加了系统复杂性但搜索体验和性能提升是巨大的。7.2 实现简单的推荐系统“猜你喜欢”是电商的标配。一个简单的实现是基于协同过滤或基于内容的推荐。基于用户行为记录用户的浏览、加入购物车、购买历史。在用户访问首页时找出与他行为相似的其他用户将这些用户喜欢而该用户未购买的商品推荐给他。这需要建立用户-物品的评分或行为矩阵。基于商品关联“购买了此商品的用户也购买了...”。这可以通过分析订单数据计算商品之间的共现频率来实现。你可以在后台定期运行一个脚本计算商品关联度并将结果缓存起来如存入Redis供前端快速读取。7.3 接入第三方服务短信/邮件服务用于用户注册验证、订单状态通知。可以使用阿里云、腾讯云的SDK它们通常有免费的测试额度。对象存储将用户上传的头像、商品图片存储到阿里云OSS、腾讯云COS或七牛云减轻服务器带宽和存储压力并提升图片加载速度。Django可以通过自定义Storage类或使用第三方库如django-storages轻松集成。缓存使用Redis缓存热点数据如首页商品列表、分类信息、用户Session等。Django的缓存框架支持多种后端配置Redis后你可以在视图层或模板层轻松使用缓存大幅提升响应速度。7.4 编写单元测试这是一个容易被忽视但极其加分的点。为你的核心模型、视图和工具函数编写测试用例能向答辩老师展示你的工程化思维和代码质量意识。# goods/tests.py from django.test import TestCase from django.urls import reverse from .models import Category, Product class ProductModelTest(TestCase): def setUp(self): self.category Category.objects.create(name测试分类) self.product Product.objects.create( name测试商品, categoryself.category, is_on_saleTrue ) def test_product_creation(self): self.assertEqual(self.product.name, 测试商品) self.assertTrue(self.product.is_on_sale) self.assertEqual(self.product.category.name, 测试分类) class ProductListViewTest(TestCase): def test_view_url_exists_at_desired_location(self): response self.client.get(/goods/) self.assertEqual(response.status_code, 200) def test_view_uses_correct_template(self): response self.client.get(reverse(goods:product_list)) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, goods/product_list.html)运行测试只需python manage.py test。一个拥有良好测试覆盖率的项目其可靠性和可维护性会得到极大提升。走到这一步你的基于Django的电商网站毕设/课设已经从一个简单的想法变成了一个结构清晰、功能完整、具备一定深度和扩展性的全栈项目。从模型设计、业务逻辑实现、并发问题处理到前端展示和部署上线你不仅实践了Django框架更体验了一个真实Web应用从设计到落地的完整生命周期。记住在答辩时清晰地阐述你的技术选型理由为什么用Django、为什么这么设计模型、重点讲解你解决的核心难题如购物车合并、订单并发控制并展示你的项目是如何运行和访问的这比单纯罗列功能点要更有说服力。祝你答辩顺利本文还有配套的精品资源点击获取