Python+Django+安卓原生开发外卖系统实战
1. 项目概述:Python+安卓双端外卖系统开发实录
去年接手了一个本地餐饮连锁的外卖系统升级项目,客户要求同时具备顾客安卓端和商家小程序管理功能。经过技术选型,最终采用Python+Django作为后端核心,配合安卓原生开发和小程序实现全套解决方案。这个技术组合在中小型外卖系统中表现出极高的性价比——Python处理订单逻辑和数据分析绰绰有余,安卓端保证顾客体验流畅,而小程序则给商家提供了零成本的管理入口。
整个系统开发周期两个月,上线后日均订单提升37%,特别在高峰时段系统稳定性远超原有PHP方案。下面我就拆解这个项目的关键技术实现,重点分享几个值得注意的架构设计决策和性能优化经验。
2. 系统架构设计解析
2.1 技术栈选型考量
后端选择Django框架主要基于三个实际考量:
- ORM层对MySQL的完美支持,省去了大量手工SQL编写
- Django REST framework可以快速构建符合微信小程序要求的API
- Python生态中有现成的支付SDK和地图API封装
测试对比发现,在同等服务器配置下,Django处理外卖系统典型的高并发查询场景(如菜单获取)比Spring Boot节省约15%的内存占用。这对需要控制成本的餐饮客户尤为重要。
安卓端采用原生开发而非Flutter等跨平台方案,主要因为:
- 外卖应用对滑动流畅度要求极高
- 需要深度集成各支付平台的SDK
- 客户后续可能有硬件对接需求(如POS机)
2.2 数据库设计要点
菜单表设计采用了纵向分表策略:
class BaseMenu(models.Model): name = models.CharField(max_length=50) category = models.ForeignKey(MenuCategory) class MenuDetail(models.Model): menu = models.OneToOneField(BaseMenu) price = models.DecimalField(max_digits=6, decimal_places=2) stock = models.PositiveIntegerField() # 其他高频变更字段将基础信息与频繁变动的价格库存分离,使高峰期的更新操作不会阻塞菜单查询。实测在500并发请求下,这种设计使订单提交响应时间从1.2秒降至0.7秒。
重要提示:外卖系统的订单表一定要设置created_at索引,且按天分表。我们曾因忽略这点导致月末查询性能下降80%
3. 核心功能实现细节
3.1 实时订单推送方案
采用WebSocket+Redis的混合方案:
- 新订单事件通过Redis Pub/Sub广播
- 各终端通过WebSocket长连接接收通知
- 安卓端额外集成华为推送服务保活
关键代码片段:
# Django consumers.py async def order_notify(self, event): await self.send_json({ 'type': 'new_order', 'order_id': event['order_id'] }) # 触发推送的service redis_client.publish('new_order', json.dumps(order_data))这个方案在3G网络环境下仍能保持2秒内的订单状态同步,且服务器压力比纯轮询模式降低60%。
3.2 小程序商家后台实现
使用Django REST framework配合微信小程序登录:
class MerchantViewSet(viewsets.ModelViewSet): authentication_classes = [WeAppAuthentication] @action(detail=False, methods=['POST']) def upload_menu(self, request): # 处理Excel菜单批量上传 try: df = pd.read_excel(request.FILES['menu_file']) # 数据清洗和导入逻辑 except Exception as e: return Response({'error': str(e)}, status=400)开发中遇到的典型问题:
- 微信登录session过期时间较短(2小时),需要前端定时刷新
- 小程序wx.uploadFile在安卓机上有概率卡死,需添加超时重试
- 表格导入时要注意浮点数精度问题(比如把12.00误存为12)
4. 性能优化关键策略
4.1 缓存设计实践
采用三级缓存策略:
- 热点数据(如店铺信息) -> Redis
- 个性化推荐数据 -> 本地SQLite
- 静态资源 -> CDN+Service Worker
缓存失效策略特别重要,我们最终采用的方案:
@cache_page(60 * 5) @vary_on_cookie def menu_view(request): # 视图逻辑 # 后台管理操作时主动清除缓存 def save_menu_item(sender, instance, **kwargs): cache.delete(f'menu_{instance.shop_id}')4.2 安卓端启动优化
通过以下措施将冷启动时间从2.3秒降至1.1秒:
- 延迟加载非首屏资源
- 将Gson解析改为手动解析关键字段
- 使用SVG替代部分PNG图标
- 预加载下一页数据
实测发现,启动时间每减少0.5秒,用户次日留存率提升约3%。这个数据让我们说服客户追加了性能优化预算。
5. 典型问题排查实录
5.1 订单重复提交问题
现象:高峰时段出现重复订单 排查过程:
- 检查前端防重点击逻辑 -> 正常
- 查看Nginx日志 -> 发现相同请求间隔<500ms
- 最终定位到负载均衡会话保持配置错误
解决方案:
class OrderCreateView(APIView): def post(self, request): # 基于客户端生成唯一请求ID request_id = request.META.get('HTTP_X_REQUEST_ID') if cache.get(request_id): return Response({'error': '重复请求'}, status=400) cache.set(request_id, True, timeout=5) # 正常下单逻辑5.2 地理位置漂移问题
商家反馈:骑手位置经常漂移2-3公里 原因排查:
- 测试各手机GPS模块 -> 正常
- 发现只发生在某品牌设备
- 最终定位是厂商省电策略导致
解决方案:
- 增加GPS信号强度检测
- 信号弱时自动切换高德IP定位
- 后台对异常轨迹进行二次校正
6. 项目部署与监控
6.1 服务器配置建议
对于日订单量3000左右的系统推荐配置:
- 前端:2核4G ×2(负载均衡)
- 后端:4核8G ×1(Django)
- 数据库:8核16G ×1(MySQL主从)
- Redis:2核4G ×1(持久化开启)
使用Supervisor管理进程时,这个配置可以轻松应对午晚双高峰(约150QPS)。
6.2 关键监控指标
我们配置了以下报警阈值:
- 订单创建响应时间 >1.5秒
- MySQL活跃连接数 >50
- Redis内存使用 >70%
- 500错误率 >0.5%
通过Prometheus+Granfana搭建的监控系统,可以在问题影响用户前及时预警。曾多次提前发现内存泄漏问题,避免了线上事故。
这个项目给我的最大启示是:外卖系统看似简单,实则每个环节都藏着魔鬼细节。比如最初没考虑商家打印机型号差异,导致热敏打印出现乱码;又或是低估了优惠券计算对数据库的压力。现在回头看,有几点特别值得新手注意:
- 一定要模拟真实高峰流量进行压测(我们用Locust模拟了500并发)
- 支付回调接口要做幂等处理
- 商家后台操作要增加二次确认
- 安卓端必须处理好各种网络切换场景
最后分享一个实用技巧:在Django admin中增加"模拟订单"功能,可以极大方便商家的员工培训。这看似小的设计,上线后让客户培训效率提升了3倍。