1. 项目背景与核心需求
外卖点餐系统在移动互联网时代已经成为餐饮行业的标配基础设施。作为开发者,我们经常需要为中小型餐饮商家快速搭建一套完整的数字化解决方案。这个基于Python和安卓的外卖点餐系统,正是针对这类需求设计的全栈解决方案。
系统包含两个核心模块:顾客端的安卓应用和商家端的小程序。顾客可以通过安卓APP浏览菜单、下单支付、查看订单状态;商家则通过小程序管理菜单、处理订单、查看经营数据。这种架构设计既考虑了顾客的使用习惯(安卓用户占比高),也照顾了商家的操作便捷性(小程序无需安装)。
提示:选择Python作为后端语言主要考虑其开发效率高、生态丰富,适合快速迭代;而安卓原生应用则能提供更好的用户体验和推送能力。
2. 技术架构设计
2.1 整体架构
系统采用经典的三层架构:
- 前端:安卓原生应用(顾客端)+ 微信小程序(商家端)
- 后端:Python + Django REST Framework
- 数据库:MySQL + Redis缓存
mermaid复制graph TD
A[安卓客户端] --> B[Python后端API]
C[微信小程序] --> B
B --> D[MySQL]
B --> E[Redis]
2.2 技术选型考量
选择Python+Django作为后端的主要优势:
- 开发效率高:Django的ORM和Admin可以快速搭建后台管理系统
- RESTful API支持完善:DRF框架提供了完整的API开发工具链
- 丰富的第三方库:支付对接、短信验证等都有成熟解决方案
安卓端采用Kotlin开发而非Java,主要因为:
- 更简洁的语法,减少样板代码
- 更好的空安全支持
- 与Java完全兼容,可以复用现有生态
3. 核心功能实现
3.1 用户认证系统
采用JWT(JSON Web Token)实现无状态认证,关键代码:
python复制# Django后端JWT生成
from rest_framework_simplejwt.tokens import RefreshToken
def get_tokens_for_user(user):
refresh = RefreshToken.for_user(user)
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
}
安卓端Token存储使用Android Keystore系统,确保安全性:
kotlin复制// 安卓端安全存储Token
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)
3.2 订单状态机
订单生命周期管理是系统的核心,我们采用状态机模式:
python复制# orders/models.py
from django_fsm import FSMField, transition
class Order(models.Model):
STATUS = (
('created', '已创建'),
('paid', '已支付'),
('preparing', '准备中'),
('ready', '已就绪'),
('delivering', '配送中'),
('completed', '已完成'),
('cancelled', '已取消')
)
status = FSMField(choices=STATUS, default='created', protected=True)
@transition(field=status, source='created', target='paid')
def pay(self):
"""支付订单"""
pass
@transition(field=status, source='paid', target='cancelled')
def cancel_after_payment(self):
"""支付后取消"""
pass
3.3 实时通知系统
使用WebSocket实现订单状态实时更新:
python复制# consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class OrderConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.order_id = self.scope['url_route']['kwargs']['order_id']
self.room_group_name = f'order_{self.order_id}'
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def order_status_update(self, event):
await self.send(text_data=json.dumps({
'type': 'status_update',
'status': event['status']
}))
安卓端使用OkHttp实现WebSocket连接:
kotlin复制// 安卓端WebSocket实现
val request = Request.Builder()
.url("ws://yourdomain.com/ws/orders/$orderId/")
.build()
val listener = object : WebSocketListener() {
override fun onMessage(webSocket: WebSocket, text: String) {
// 处理订单状态更新
}
}
val ws = OkHttpClient().newWebSocket(request, listener)
4. 商家小程序开发
4.1 小程序技术栈
商家端采用微信小程序,主要考虑:
- 商家使用门槛低,无需安装
- 开发成本低,迭代速度快
- 微信生态内传播方便
使用Taro框架实现跨端开发,一套代码可同时发布到微信、支付宝等平台:
javascript复制// 订单管理页面
import Taro from '@tarojs/taro'
import { AtList, AtListItem } from 'taro-ui'
export default class OrderList extends Taro.Component {
state = {
orders: []
}
componentDidMount() {
this.fetchOrders()
}
fetchOrders = async () => {
const res = await Taro.request({
url: 'https://api.yourdomain.com/orders/',
header: {
'Authorization': `Bearer ${Taro.getStorageSync('token')}`
}
})
this.setState({ orders: res.data })
}
render() {
return (
<AtList>
{this.state.orders.map(order => (
<AtListItem
title={`订单#${order.id}`}
note={`状态: ${order.status}`}
arrow='right'
onClick={() => Taro.navigateTo({
url: `/pages/order/detail?id=${order.id}`
})}
/>
))}
</AtList>
)
}
}
4.2 菜单管理功能
商家最核心的需求是菜单管理,我们实现了:
- 分类管理
- 菜品CRUD
- 库存预警
- 定时上下架
后端API设计:
python复制# api/views.py
from rest_framework import viewsets
from .models import MenuItem, Category
from .serializers import MenuItemSerializer, CategorySerializer
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializer
class MenuItemViewSet(viewsets.ModelViewSet):
queryset = MenuItem.objects.select_related('category')
serializer_class = MenuItemSerializer
def get_queryset(self):
queryset = super().get_queryset()
category_id = self.request.query_params.get('category')
if category_id:
queryset = queryset.filter(category_id=category_id)
return queryset
5. 性能优化实践
5.1 数据库优化
针对外卖系统读多写少的特点,我们采取以下措施:
- 使用Django的select_related/prefetch_related减少查询次数
- 高频访问数据(如菜单)使用Redis缓存
- 订单表按月份分表
python复制# 使用缓存装饰器
from django.core.cache import cache
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
class MenuViewSet(viewsets.ReadOnlyModelViewSet):
@method_decorator(cache_page(60*15)) # 缓存15分钟
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
5.2 安卓端优化
- 图片加载使用Glide,自动处理缓存和压缩
- 列表使用RecyclerView + Paging3实现分页加载
- 网络请求使用协程避免主线程阻塞
kotlin复制// 使用协程加载数据
lifecycleScope.launch {
try {
val response = withContext(Dispatchers.IO) {
apiService.getRestaurants(page = nextPage)
}
// 更新UI
} catch (e: Exception) {
// 错误处理
}
}
6. 部署与运维
6.1 服务器部署
使用Docker Compose部署整个系统:
yaml复制version: '3'
services:
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: yourpassword
volumes:
- db_data:/var/lib/mysql
redis:
image: redis:alpine
app:
build: .
command: gunicorn yourproject.wsgi:application --bind 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
- redis
volumes:
db_data:
6.2 监控与日志
使用Sentry收集错误日志:
python复制# settings.py
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
dsn="your_dsn",
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
send_default_pii=True
)
安卓端也集成Sentry:
kotlin复制SentryAndroid.init(this) { options ->
options.dsn = "your_dsn"
options.tracesSampleRate = 1.0
}
7. 安全防护措施
7.1 常见攻击防护
- SQL注入:使用Django ORM自动防护
- XSS:模板自动转义 + 前端sanitize
- CSRF:Django中间件 + 小程序header校验
python复制# 自定义权限类
from rest_framework.permissions import BasePermission
class IsOwnerOrAdmin(BasePermission):
"""
只允许对象所有者或管理员访问
"""
def has_object_permission(self, request, view, obj):
return obj.owner == request.user or request.user.is_staff
7.2 支付安全
- 支付参数签名验证
- 支付结果异步通知校验
- 敏感操作二次验证
python复制# 支付签名验证
import hashlib
def verify_signature(params, secret_key):
sign = params.pop('sign')
query_string = '&'.join(
f'{k}={v}' for k, v in sorted(params.items())
)
expected_sign = hashlib.md5(
(query_string + secret_key).encode()
).hexdigest()
return sign == expected_sign
8. 项目扩展方向
在实际部署多个商家版本后,可以考虑以下扩展:
- 多商家平台模式:开发管理后台,支持多个商家入驻
- 配送系统集成:对接达达、蜂鸟等第三方配送
- 数据分析看板:使用Apache Superset构建商家数据分析
- 会员系统:积分、优惠券等营销工具
python复制# 多租户实现示例
from django_tenants.models import TenantMixin, DomainMixin
class Client(TenantMixin):
name = models.CharField(max_length=100)
paid_until = models.DateField()
on_trial = models.BooleanField()
class Domain(DomainMixin):
pass
这个Python+安卓的外卖系统解决方案,从实际商户需求出发,平衡了开发效率与用户体验。在多个实际项目中,这种技术组合已被验证能够快速响应商户需求,同时保证系统的稳定性和可扩展性。
