尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于Django与微信小程序的健康饮食推荐系统开发实践

基于Django与微信小程序的健康饮食推荐系统开发实践 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_length64, uniqueTrue) height models.FloatField() # 厘米 weight models.FloatField() # 公斤 target models.CharField(choicesTARGET_CHOICES) # 减脂/增肌/维持 class FoodItem(models.Model): name models.CharField(max_length100) 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_deletemodels.CASCADE) food models.ForeignKey(FoodItem, on_deletemodels.CASCADE) portion models.FloatField() # 份量系数 recorded_at models.DateTimeField(auto_now_addTrue)特别注意微信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_openidopenid, 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_caloriesF(calories)*0.8 # 考虑烹饪损失 ).filter( total_calories__ltetarget_calories*1.2, total_calories__gtetarget_calories*0.8 ) # 根据用户目标调整筛选条件 if self.user.target weight_loss: foods foods.filter(fat__lte10) elif self.user.target muscle_gain: foods foods.filter(protein__gte20) 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__lt300).values(name, calories)混合开发陷阱小程序端的本地缓存与服务器状态可能不同步时间戳处理要注意时区问题建议全部使用UTC微信用户头像需要特殊处理防盗链推荐算法冷启动问题新用户没有历史数据时采用基于规则的推荐可以预置几套典型用户画像上班族/学生/健身人士通过简单的问卷收集初始偏好这个项目最有趣的部分是看到算法推荐与实际饮食的差距。我们发现用户对健康食品的接受度往往比预期低后来通过添加放纵餐机制每周允许一次高热量推荐显著提升了用户粘性。
返回列表