1. 项目概述:基于Django的微信小程序健康饮食推荐平台
这个项目本质上是一个结合了Python后端技术与微信小程序前端的智能推荐系统。我去年为一家健康管理机构开发过类似平台,核心目标是通过算法分析用户的身体数据、饮食习惯和健康目标,提供个性化的饮食建议。
微信小程序作为前端载体具有天然优势:无需安装、即用即走,特别适合饮食记录这种高频低粘性的场景。而后端选择Django框架则是因为其完善的ORM系统能快速处理复杂的营养数据关系,自带的管理后台也方便营养师团队维护菜品数据库。
2. 技术架构设计
2.1 前后端分离架构
我们采用典型的前后端分离设计:
- 前端:微信小程序 + WeUI组件库
- 后端:Django REST Framework构建API
- 通信:HTTPS + JWT认证
- 数据库:MySQL(关系型)+ Redis(缓存)
这种架构的优势在于:
- 小程序端可以独立迭代UI而不影响后端逻辑
- DRF提供的Browsable API方便调试
- 双数据库设计兼顾了复杂查询和高并发场景
2.2 核心数据模型设计
在models.py中需要建立的关键模型包括:
class UserProfile(models.Model): wechat_openid = models.CharField(max_length=64, unique=True) height = models.FloatField() # 厘米 weight = models.FloatField() # 公斤 target = models.CharField(choices=TARGET_CHOICES) # 减脂/增肌/维持 class FoodItem(models.Model): name = models.CharField(max_length=100) calories = models.FloatField() # 千卡 protein = models.FloatField() # 克 carbs = models.FloatField() # 克 fat = models.FloatField() # 克 tags = TaggableManager() # django-taggit扩展 class MealRecord(models.Model): user = models.ForeignKey(UserProfile, on_delete=models.CASCADE) food = models.ForeignKey(FoodItem, on_delete=models.CASCADE) portion = models.FloatField() # 份量系数 recorded_at = models.DateTimeField(auto_now_add=True)特别注意:微信OpenID是敏感信息,实际存储时需要加密处理。我们使用django-cryptography库进行字段级加密。
3. 核心功能实现
3.1 微信小程序登录集成
在Django端需要实现微信登录接口:
# views.py from rest_framework.views import APIView import requests class WechatLogin(APIView): def post(self, request): code = request.data.get('code') # 调用微信接口获取openid resp = requests.get( 'https://api.weixin.qq.com/sns/jscode2session', params={ 'appid': settings.WECHAT_APPID, 'secret': settings.WECHAT_SECRET, 'js_code': code, 'grant_type': 'authorization_code' } ) openid = resp.json().get('openid') # 查找或创建用户 user, created = UserProfile.objects.get_or_create( wechat_openid=openid, defaults={'height': 170, 'weight': 60} # 初始默认值 ) # 生成JWT token token = generate_jwt(user) return Response({'token': token})常见问题处理:
- 微信接口调用频率限制:需要添加redis缓存
- 新用户引导:通过created标志触发问卷页面
- 安全防护:需要验证referer并限制IP频率
3.2 推荐算法实现
核心推荐逻辑在recommender.py中:
class DietRecommender: def __init__(self, user): self.user = user self.tdee = self.calculate_tdee() def calculate_tdee(self): """计算每日总能量消耗""" bmr = 10*self.user.weight + 6.25*self.user.height - 5*30 + 5 # Mifflin公式 activity_factor = 1.55 # 中等活动量 return bmr * activity_factor def recommend_meal(self, meal_type): """根据餐型(早餐/午餐/晚餐)推荐""" target_calories = { 'breakfast': self.tdee * 0.3, 'lunch': self.tdee * 0.4, 'dinner': self.tdee * 0.3 }[meal_type] # 从数据库筛选符合条件的食物 foods = FoodItem.objects.annotate( total_calories=F('calories')*0.8 # 考虑烹饪损失 ).filter( total_calories__lte=target_calories*1.2, total_calories__gte=target_calories*0.8 ) # 根据用户目标调整筛选条件 if self.user.target == 'weight_loss': foods = foods.filter(fat__lte=10) elif self.user.target == 'muscle_gain': foods = foods.filter(protein__gte=20) return foods.order_by('?')[:3] # 随机返回3个选项算法优化技巧:
- 使用annotate提前计算营养值
- 通过F表达式避免多次查询
- order_by('?')实现简单随机推荐
- 实际项目中应该加入协同过滤算法
4. 微信小程序端关键实现
4.1 页面结构设计
建议采用微信小程序标准目录结构:
pages/ index/ # 首页 record/ # 饮食记录 recommend/ # 推荐页面 profile/ # 个人中心 components/ food-card/ # 统一菜品卡片 calorie-bar/ # 热量进度条4.2 与Django后端交互示例
获取今日推荐的小程序端代码:
// pages/recommend/recommend.js Page({ data: { meals: [] }, onLoad() { this.getRecommendations() }, getRecommendations() { const token = wx.getStorageSync('token') wx.request({ url: 'https://yourdomain.com/api/recommend/', header: { 'Authorization': `Bearer ${token}` }, success: (res) => { this.setData({meals: res.data}) }, fail: (err) => { wx.showToast({title: '获取推荐失败', icon: 'error'}) } }) } })性能优化点:
- 使用wx.setStorageSync缓存用户数据
- 合并请求减少接口调用
- 添加loading状态提升用户体验
5. 部署与运维实践
5.1 生产环境部署
推荐使用Docker Compose部署:
# docker-compose.yml version: '3' services: app: build: . command: gunicorn config.wsgi:application --bind 0.0.0.0:8000 volumes: - .:/code ports: - "8000:8000" depends_on: - redis - db db: image: mysql:5.7 environment: MYSQL_DATABASE: diet MYSQL_ROOT_PASSWORD: yourpassword volumes: - db_data:/var/lib/mysql redis: image: redis:alpine volumes: db_data:关键配置项:
- 使用Gunicorn替代开发服务器
- 配置MySQL连接池
- 设置Redis缓存
- 启用HTTPS(微信小程序强制要求)
5.2 性能监控
建议添加:
- Django-debug-toolbar(开发环境)
- Sentry错误监控
- Prometheus + Grafana监控系统
6. 实际开发中的经验教训
微信小程序限制问题:
- 域名必须备案且支持HTTPS
- 图片资源需要下载到本地才能显示
- 表单提交有大小限制
Django优化技巧:
# 糟糕的查询 foods = [food for food in FoodItem.objects.all() if food.calories < 300] # 优化后的查询 foods = FoodItem.objects.filter(calories__lt=300).values('name', 'calories')混合开发陷阱:
- 小程序端的本地缓存与服务器状态可能不同步
- 时间戳处理要注意时区问题(建议全部使用UTC)
- 微信用户头像需要特殊处理(防盗链)
推荐算法冷启动问题:
- 新用户没有历史数据时,采用基于规则的推荐
- 可以预置几套典型用户画像(上班族/学生/健身人士)
- 通过简单的问卷收集初始偏好
这个项目最有趣的部分是看到算法推荐与实际饮食的差距。我们发现用户对"健康食品"的接受度往往比预期低,后来通过添加"放纵餐"机制(每周允许一次高热量推荐)显著提升了用户粘性。