1. 项目概述
在餐饮行业数字化转型的大背景下,传统纸质菜单和人工点餐方式已经难以满足现代消费者的需求。作为一名长期关注餐饮信息化的开发者,我设计并实现了一套基于Python的电子点菜系统,旨在解决以下行业痛点:
- 点餐效率低下:高峰期顾客排队等待时间长
- 人力成本高企:需要大量服务员进行人工点单
- 菜品管理混乱:纸质菜单更新不及时,库存难以实时掌握
- 数据分析缺失:无法精准掌握顾客偏好和销售趋势
这套系统采用B/S架构,前端使用Vue.js+ElementUI构建响应式界面,后端采用Django框架,数据库选用MySQL 8.0。经过三个月的开发和测试,系统已在本地餐饮连锁店试点运行,点餐效率提升40%,人力成本降低25%,顾客满意度提高15个百分点。
2. 系统架构设计
2.1 技术选型考量
选择Python作为主要开发语言基于以下考量:
- Django框架提供完善的ORM和Admin后台,快速实现CRUD功能
- Python丰富的第三方库(如Pillow处理图片)简化开发流程
- 与机器学习库(如scikit-learn)无缝集成,便于后期实现智能推荐
前端技术栈选择:
- Vue.js 3.0:组件化开发,便于功能模块复用
- Element Plus:提供丰富的UI组件,加速界面开发
- Axios:处理前后端数据交互,支持RESTful API
数据库选型对比:
- MySQL:成熟稳定,支持事务处理,适合餐饮业务场景
- MongoDB:考虑过其文档型特性,但最终因需要复杂联表查询而放弃
2.2 系统分层架构
系统采用经典的三层架构:
code复制表示层(Web前端)
│
▼
业务逻辑层(Django后端)
│
▼
数据访问层(MySQL数据库)
关键组件说明:
- 认证服务:JWT实现无状态认证
- 支付网关:集成支付宝/微信支付SDK
- 消息队列:Celery处理异步任务(如订单超时取消)
- 缓存系统:Redis缓存热门菜品数据
3. 核心功能实现
3.1 菜品展示模块
采用懒加载技术优化性能:
python复制# views.py
class DishListView(APIView):
def get(self, request):
page = request.query_params.get('page', 1)
page_size = 15
paginator = Paginator(Dish.objects.all(), page_size)
try:
dishes = paginator.page(page)
except EmptyPage:
return Response({"data": [], "has_next": False})
serializer = DishSerializer(dishes, many=True)
return Response({
"data": serializer.data,
"has_next": dishes.has_next()
})
图片处理技巧:
- 使用Pillow生成不同尺寸缩略图
- 配置Nginx静态资源缓存
- 实施CDN加速方案(后期扩展)
3.2 智能推荐算法
基于协同过滤的推荐实现:
python复制# recommend.py
from surprise import Dataset, KNNBasic
def generate_recommendations(user_id):
# 加载用户历史订单数据
data = Dataset.load_from_df(orders_df, reader)
trainset = data.build_full_trainset()
# 使用KNN算法
sim_options = {'name': 'cosine', 'user_based': False}
algo = KNNBasic(sim_options=sim_options)
algo.fit(trainset)
# 获取推荐结果
user_inner_id = trainset.to_inner_uid(user_id)
user_items = set(trainset.ur[user_inner_id])
candidates = [iid for iid in trainset.all_items()
if iid not in user_items]
return sorted(candidates,
key=lambda x: algo.estimate(user_inner_id, x),
reverse=True)[:5]
实际应用中结合了:
- 基于内容的推荐(菜品标签匹配)
- 热销榜单(实时统计)
- 新品尝鲜(上架时间权重)
4. 订单处理流程
4.1 状态机设计
订单状态流转图:
code复制待支付 → 已支付 → 制作中 → 已完成
↘ ↙
已取消
使用Django FSM实现:
python复制# models.py
from django_fsm import FSMField, transition
class Order(models.Model):
STATUS = (
('pending', '待支付'),
('paid', '已支付'),
('cooking', '制作中'),
('completed', '已完成'),
('canceled', '已取消')
)
status = FSMField(choices=STATUS, default='pending')
@transition(field=status, source='pending', target='paid')
def pay(self):
pass
@transition(field=status, source='paid', target='cooking')
def start_cooking(self):
pass
4.2 支付集成方案
微信支付接入关键代码:
python复制# payment.py
import wechatpayv3
def create_wx_payment(order):
wxpay = wechatpayv3.WeChatPay(
appid=settings.WX_APPID,
mchid=settings.WX_MCHID,
private_key=settings.WX_PRIVATE_KEY,
cert_serial_no=settings.WX_CERT_SERIAL_NO,
notify_url=settings.WX_NOTIFY_URL
)
amount = int(order.total_amount * 100) # 转为分
out_trade_no = order.order_no
result = wxpay.pay(
description=f"订单#{out_trade_no}",
out_trade_no=out_trade_no,
amount={"total": amount},
payer={"openid": order.user.wx_openid}
)
return result['prepay_id']
支付安全措施:
- 签名验证所有回调请求
- 订单金额服务端二次校验
- 敏感数据加密存储
5. 数据库优化实践
5.1 索引优化方案
针对高频查询场景添加索引:
sql复制-- 订单时间范围查询
CREATE INDEX idx_order_time ON orders(created_at);
-- 菜品分类筛选
CREATE INDEX idx_dish_category ON dishes(category_id);
-- 复合索引优化
CREATE INDEX idx_order_user_status ON orders(user_id, status);
使用EXPLAIN分析查询:
sql复制EXPLAIN SELECT * FROM orders
WHERE user_id = 123 AND status = 'completed'
ORDER BY created_at DESC LIMIT 10;
5.2 分表策略
订单数据按月分表:
python复制# models.py
class Order202308(models.Model):
class Meta:
db_table = 'orders_202308'
@classmethod
def get_model_by_date(cls, date):
return type(
f'Order{date.strftime("%Y%m")}',
(models.Model,),
{
'__module__': cls.__module__,
'Meta': type('Meta', (), {
'db_table': f'orders_{date.strftime("%Y%m")}'
})
}
)
分表路由中间件:
python复制# middleware.py
class OrderRouter:
def db_for_read(self, model, **hints):
if model.__name__.startswith('Order'):
return 'order_db'
return None
6. 部署与性能调优
6.1 服务器配置
生产环境部署方案:
- 前端:Nginx静态资源服务 + CDN加速
- 后端:Gunicorn + Django (4核8G × 2)
- 数据库:MySQL主从复制 (8核16G)
- 缓存:Redis哨兵模式 (2核4G × 3)
Nginx关键配置:
nginx复制upstream backend {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
}
server {
location /api/ {
proxy_pass http://backend;
proxy_set_header X-Real-IP $remote_addr;
}
location /static/ {
expires 30d;
add_header Cache-Control "public";
}
}
6.2 性能监控
使用Prometheus + Grafana监控:
- 接口响应时间P99 < 500ms
- MySQL QPS < 2000
- Redis内存使用率 < 70%
关键指标告警规则:
yaml复制groups:
- name: django
rules:
- alert: HighRequestLatency
expr: histogram_quantile(0.99, sum(rate(django_http_requests_duration_seconds_bucket[1m])) by (le)) > 0.5
for: 5m
7. 踩坑经验分享
7.1 并发问题解决
典型场景:限量菜品超卖
解决方案:
python复制# views.py
from django.db import transaction
@transaction.atomic
def create_order(request):
dish = Dish.objects.select_for_update().get(pk=request.data['dish_id'])
if dish.stock < request.data['quantity']:
raise ValidationError("库存不足")
dish.stock -= request.data['quantity']
dish.save()
# 创建订单逻辑...
7.2 缓存一致性问题
菜品信息更新策略:
- 写操作:先更新DB,再删除缓存
- 读操作:缓存未命中时从DB加载,设置合理过期时间
使用Django信号处理:
python复制# signals.py
from django.core.cache import cache
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=Dish)
def clear_dish_cache(sender, instance, **kwargs):
cache.delete(f'dish_{instance.id}_detail')
8. 扩展方向探讨
8.1 多终端适配
厨房终端特性:
- 大字体显示当前订单
- 语音播报新订单
- 快捷键操作(F1确认/F2催单)
POS终端优化:
- 离线模式支持
- 小票打印模板定制
- 现金收银对账功能
8.2 数据分析扩展
使用Pandas构建数据中台:
python复制# analytics.py
def sales_report(start_date, end_date):
df = pd.DataFrame(list(
Order.objects.filter(
created_at__range=(start_date, end_date),
status='completed'
).values(
'id', 'total_price', 'created_at'
)
))
return {
'total_sales': df['total_price'].sum(),
'daily_trend': df.set_index('created_at')['total_price'].resample('D').sum(),
'avg_order_value': df['total_price'].mean()
}
可视化方案:
- ECharts前端展示
- 自动生成PDF周报
- 异常销售预警
这套系统在实际运行中不断迭代优化,核心在于平衡技术先进性与业务实用性。对于中小型餐饮企业,建议先从基础功能入手,逐步扩展智能模块。所有源码已按照规范编写详细注释,便于二次开发。