1. 项目概述:基于Django的蛋糕商城开发实战
十年前我刚接触Web开发时,用Django做的第一个项目就是电商系统。如今看到这个蛋糕购物商城的需求,不禁想起当年调试购物车功能连续熬的三个通宵。这个毕业设计项目采用Django全栈开发,包含完整的商品展示、用户管理、订单处理等电商核心功能模块,特别适合计算机专业学生作为毕业设计选题。
相比常见的图书管理系统,蛋糕商城在业务复杂度上更贴近真实商业场景。比如需要处理商品规格选择(6寸/8寸蛋糕)、配送时间预约等特色需求,这对数据库设计和业务逻辑实现都提出了更高要求。项目采用经典的MVC架构,前端使用Bootstrap保证响应式布局,后端Django框架提供稳健的ORM和路由支持,MySQL作为数据存储方案。
2. 技术架构设计
2.1 Django框架选型考量
选择Django而非Flask等轻量级框架主要基于三点考虑:
- 内置功能完整:自带Admin后台、ORM、用户认证等组件,减少重复造轮子
- 开发效率高:通过python manage.py startapp命令即可快速生成标准化应用结构
- 文档生态丰富:作为最流行的Python Web框架,遇到问题更容易找到解决方案
特别对于毕业设计这类有时间限制的项目,使用Django的scaffolding功能可以快速搭建出基础框架。我在项目中实际测试,从零开始到完成第一个商品列表API接口,仅用了不到2小时。
2.2 数据库设计要点
蛋糕商城的数据库设计有几个特殊点需要注意:
python复制# models.py 核心模型示例
class CakeProduct(models.Model):
name = models.CharField(max_length=100)
base_price = models.DecimalField(max_digits=8, decimal_places=2)
# 蛋糕特有属性
size_choices = [(6,'6寸'),(8,'8寸'),(10,'10寸')]
size = models.IntegerField(choices=size_choices)
flavor = models.ForeignKey('Flavor', on_delete=models.SET_NULL, null=True)
# 方法计算最终价格(考虑尺寸加成)
def get_final_price(self):
return self.base_price * (self.size / 6) # 6寸为基础价格
商品表设计时需要特别注意:
- 价格字段必须使用Decimal而非Float,避免浮点精度问题
- 尺寸使用choice字段限定可选值
- 建立口味单独表并通过外键关联,方便扩展
2.3 前后端交互设计
项目采用传统服务端渲染模式而非前后端分离,主要出于以下考虑:
- 毕业设计展示时需要完整可见的前端页面
- 减少配置webpack等前端工具链的时间成本
- Django模板系统足够满足基础交互需求
关键交互流程如加入购物车采用AJAX实现:
javascript复制// 静态文件中的ajax调用
$('.add-to-cart').click(function(){
$.ajax({
url: '/cart/add/' + productId,
success: function(data){
$('#cart-count').text(data.total_items)
}
})
})
3. 核心功能实现细节
3.1 用户系统实现
用户模块采用Django内置的auth系统扩展实现,重点改造了:
- 注册流程增强:
python复制# forms.py
class SignUpForm(UserCreationForm):
phone = forms.CharField(max_length=11)
address = forms.CharField(widget=forms.Textarea)
class Meta:
model = User
fields = ('username', 'phone', 'address', 'password1', 'password2')
- 权限控制方案:
- 普通用户:只能查看/购买商品
- 店员用户:可管理订单状态
- 管理员:完整后台权限
通过自定义装饰器实现权限控制:
python复制def staff_required(view_func):
def wrapper(request, *args, **kwargs):
if not request.user.is_staff:
return HttpResponseForbidden()
return view_func(request, *args, **kwargs)
return wrapper
3.2 商品展示系统
商品展示有三个技术亮点值得注意:
- 多条件筛选:
python复制# views.py
def product_list(request):
queryset = CakeProduct.objects.all()
if 'size' in request.GET:
queryset = queryset.filter(size=request.GET['size'])
if 'min_price' in request.GET:
queryset = queryset.filter(base_price__gte=request.GET['min_price'])
return render(request, 'list.html', {'products': queryset})
- 分页优化:
使用Django内置Paginator类时,一定要设置合理的page_size:
python复制paginator = Paginator(products, 12) # 每页12个商品
- 图片处理:
- 使用Pillow库生成缩略图
- 配置MEDIA_ROOT处理上传文件
- 开发时需注意DEBUG=True时的媒体文件服务配置
3.3 购物车与订单系统
购物车实现采用混合存储策略:
- 未登录用户:使用session存储
- 已登录用户:存入数据库
关键数据结构设计:
python复制class CartItem(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product = models.ForeignKey(CakeProduct, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
selected_options = JSONField() # 存储选择的糖度、祝福语等
@property
def total_price(self):
return self.product.get_final_price() * self.quantity
订单状态机设计要点:
python复制ORDER_STATUS = [
('unpaid', '待支付'),
('paid', '已支付'),
('baking', '制作中'),
('delivering', '配送中'),
('completed', '已完成'),
('cancelled', '已取消')
]
class Order(models.Model):
status = models.CharField(max_length=20, choices=ORDER_STATUS, default='unpaid')
def can_cancel(self):
return self.status in ['unpaid', 'paid']
4. 开发经验与避坑指南
4.1 调试技巧实录
- 模板变量不显示:
- 检查render函数的context字典key是否匹配
- 在模板中使用{{ debug }}查看所有可用变量
- 数据库查询优化:
- 使用select_related/prefetch_related减少查询次数
- Django Debug Toolbar是必备调试工具
- 常见异常处理:
- DoesNotExist异常:使用get_object_or_404快捷方法
- 多线程下send_mail问题:配置EMAIL_BACKEND为django.core.mail.backends.smtp.EmailBackend
4.2 部署注意事项
- 静态文件收集:
bash复制python manage.py collectstatic
务必配置好STATIC_ROOT和STATIC_URL
- 生产环境配置:
- DEBUG必须设为False
- ALLOWED_HOSTS需要配置真实域名
- 数据库换用PostgreSQL性能更佳
- 安全加固:
- 设置SECRET_KEY环境变量
- 使用django-environ管理敏感配置
- 定期更新依赖包版本
5. 毕业设计扩展建议
这个基础版本可以进一步扩展的方向:
- 微信小程序端:
- 使用Django REST framework开发API
- 小程序端调用接口实现跨平台
- 智能推荐系统:
- 基于用户历史购买记录实现协同过滤
- 使用surprise库实现推荐算法
- 配送轨迹跟踪:
- 集成第三方地图API
- 使用WebSocket实现实时位置更新
我在实际部署时发现,当商品图片较多时,Nginx默认的client_max_body_size可能导致上传失败。解决方法是在nginx.conf中添加:
code复制client_max_body_size 20M;
这个细节很多教程都不会提到,但实际开发中经常会遇到。