1. 项目概述:基于Python的餐饮配送系统设计与实现
最近在帮一家本地连锁餐厅升级他们的订单管理系统,用Python+Flask+Django混搭架构做了套外卖配送系统。这套系统不仅要处理顾客下单流程,还得兼顾后厨分单、骑手调度和员工绩效统计。相比市面上通用的SaaS解决方案,自主开发能完美适配餐厅的特殊业务流程,比如他们的"高峰期动态加价"和"会员积分折现"规则。
从技术选型来看,Flask负责轻量级的API服务,Django则用来搭建后台管理系统。这种组合既保证了订单处理的高并发性能,又提供了完善的后台管理功能。特别在骑手自动派单算法上,我们基于实时路况数据做了优化,比原有手动派单效率提升了40%左右。
2. 系统架构设计
2.1 技术栈选型考量
选择Python生态主要基于三个因素:
- 开发团队对Python系框架更熟悉,能快速迭代
- Django自带的Admin后台能节省30%管理界面开发量
- Flask的灵活性适合处理高并发的订单请求
数据库采用PostgreSQL+Redis组合:
- PostgreSQL存储核心业务数据(用户/订单/菜品)
- Redis缓存菜单数据和骑手实时位置
- 使用Django ORM统一数据访问层
2.2 核心模块划分
graph TD A[用户端] --> B(菜品展示) A --> C(购物车) A --> D(订单支付) B --> E[Redis缓存] D --> F[PostgreSQL] G[管理后台] --> H(订单管理) G --> I(骑手调度) G --> J(数据统计) H --> F I --> K[高德地图API](注:实际开发中删除了mermaid图表,改用文字说明)
系统主要包含三大模块:
- 用户前端:Vue.js构建的H5页面,包含菜单浏览、购物车、订单跟踪等功能
- API服务层:Flask实现的RESTful接口,处理核心业务逻辑
- 管理后台:Django Admin深度定制,包含:
- 实时订单监控看板
- 骑手自动派单算法
- 销售数据多维分析
3. 关键功能实现细节
3.1 动态定价算法
餐厅要求在午晚高峰时段(11:00-13:00,17:00-19:00)自动上浮配送费5%-15%。实现逻辑:
def calculate_delivery_fee(base_fee, order_time): peak_hours = [ (datetime.time(11,0), datetime.time(13,0)), (datetime.time(17,0), datetime.time(19,0)) ] is_peak = any(start <= order_time.time() <= end for start, end in peak_hours) if is_peak: # 根据实时订单量动态调整加价比例 current_orders = get_current_order_count() if current_orders > 50: return base_fee * 1.15 elif current_orders > 30: return base_fee * 1.10 return base_fee * 1.05 return base_fee重要提示:动态定价需要在前端明显位置提示用户,避免客诉
3.2 骑手派单优化
结合高德地图API实现的智能派单流程:
- 获取待分配订单的配送地址
- 查询半径3km内的空闲骑手
- 计算每位骑手到商家的预估时间
- 综合考量:
- 骑手当前负载(未完成订单数)
- 历史配送准时率
- 交通工具类型(电动车/摩托车)
def dispatch_order(order): riders = Rider.objects.filter( status='idle', location__distance_lte=(order.restaurant.location, 3000) ).annotate( eta=Func( F('location'), order.restaurant.location, function='ST_Distance' ) ).order_by('eta')[:5] best_choice = max( riders, key=lambda r: r.performance_score / (r.current_orders + 1) ) assign_order_to_rider(order, best_choice)4. 性能优化实践
4.1 菜单缓存策略
实测发现菜单API占用了60%的请求量,采用三级缓存方案:
- 客户端本地缓存(1小时)
- CDN边缘缓存(5分钟)
- Redis内存缓存(实时更新)
@cache.memoize(timeout=300) def get_menu(restaurant_id): menu = Menu.objects.filter( restaurant_id=restaurant_id, is_active=True ).prefetch_related('categories__items') return serialize_menu(menu)4.2 数据库查询优化
发现订单列表页存在N+1查询问题,通过以下方式解决:
- 使用select_related获取外键关联
- prefetch_related预取多对多关系
- 添加数据库索引:
CREATE INDEX idx_order_status ON orders(status); CREATE INDEX idx_order_created ON orders(created_at DESC);
5. 员工管理模块
5.1 权限控制系统
使用Django内置的权限系统扩展:
class StaffPermissionMixin: def dispatch(self, request, *args, **kwargs): if not request.user.has_perm('orders.view_dashboard'): return HttpResponseForbidden() return super().dispatch(request, *args, **kwargs) # 权限颗粒度控制 PERMISSION_MAP = { 'cashier': ['orders.add_order', 'orders.change_order'], 'kitchen': ['orders.view_order', 'orders.change_orderstatus'], 'rider': ['orders.view_order', 'orders.change_deliverystatus'] }5.2 绩效统计看板
后厨人员绩效评估指标:
- 订单平均处理时长
- 退单率
- 菜品评价均分
骑手绩效维度:
- 准时送达率
- 平均配送时长
- 客户评分
使用Django ORM的聚合函数实现:
def get_kitchen_performance(start_date, end_date): return Order.objects.filter( created_at__range=(start_date, end_date), status='completed' ).annotate( duration=ExpressionWrapper( F('completed_at') - F('confirmed_at'), output_field=DurationField() ) ).aggregate( avg_duration=Avg('duration'), cancel_rate=Count( Case( When(status='cancelled', then=1), output_field=IntegerField() ) ) / Count('id') )6. 部署实战经验
6.1 高可用架构
最终采用的部署方案:
- Nginx负载均衡(2台4核8G服务器)
- Gunicorn运行Flask应用(每个worker 2线程)
- Django后台独立部署(uWSGI)
- PostgreSQL主从复制
- Redis哨兵模式
6.2 踩坑记录
微信支付回调问题:
- 必须支持HTTPS
- 回调地址不能带端口号
- 处理时间需控制在2秒内
地理围栏精度:
- 高德API的圆形围栏存在50-100米误差
- 改用多边形围栏后解决
订单状态同步:
- 最初采用短轮询导致性能问题
- 改用WebSocket后CPU负载下降70%
7. 扩展功能建议
智能推荐系统:
- 基于用户历史订单推荐菜品
- 实现协同过滤算法
语音订单处理:
- 集成ASR识别语音订单
- 自动生成订单草稿
供应链对接:
- 库存自动预警
- 智能采购预测
这套系统上线后,餐厅的日均订单处理能力从200单提升到500单,人力成本降低30%。最大的收获是验证了Python在中小型O2O系统中的可行性,特别是在快速迭代和数据处理方面的优势。