1. 项目背景与核心需求
苏菜作为中国八大菜系之一,以其精致的刀工、鲜美的口味和讲究的养生理念闻名。随着健康饮食理念的普及,越来越多的人希望了解苏菜背后的营养价值和健康搭配方法。这个项目正是基于这样的需求,旨在构建一个结合Python后端技术与Vue前端框架的苏菜与健康知识分享平台。
在技术选型上,我们选择了PyCharm作为开发IDE,后端采用Django+Flask混合架构。这种组合既能利用Django强大的全功能特性,又能发挥Flask在特定接口上的轻量级优势。前端使用Vue.js实现响应式交互,为用户提供流畅的浏览体验。
提示:Django和Flask的混合使用需要特别注意路由配置和静态文件处理,建议将Flask作为Django项目的子模块运行。
2. 技术架构设计
2.1 前后端分离架构
项目采用典型的前后端分离架构:
- 前端:Vue 3 + Vue Router + Axios + Element Plus
- 后端:Django REST framework + Flask微服务
- 数据库:PostgreSQL(主库)+ Redis(缓存)
- 开发工具:PyCharm Professional(后端)+ VS Code(前端)
python复制# Django项目核心settings.py配置示例
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders', # 跨域支持
'food.apps.FoodConfig', # 菜品模块
'health.apps.HealthConfig', # 健康模块
]
# Flask微服务集成示例
from flask import Flask
flask_app = Flask(__name__)
@flask_app.route('/api/nutrition')
def get_nutrition():
# 营养计算微服务
return {'status': 'success'}
2.2 Django与Flask的协同工作
Django作为主框架负责:
- 用户认证系统
- 后台管理界面
- 主要业务逻辑
- 数据库ORM管理
Flask作为微服务负责:
- 实时营养计算
- 菜品热量分析
- 个性化推荐引擎
注意:两个框架共用数据库时需要确保Session管理的一致性,建议使用Redis作为共享Session存储。
3. 核心功能实现
3.1 苏菜数据库建模
python复制# models.py 菜品核心模型
from django.db import models
from django.contrib.postgres.fields import ArrayField
class Cuisine(models.Model):
CATEGORY_CHOICES = [
('SZ', '苏州菜'),
('WX', '无锡菜'),
('YZ', '扬州菜'),
]
name = models.CharField(max_length=100, verbose_name="菜品名称")
origin = models.CharField(max_length=50, choices=CATEGORY_CHOICES)
ingredients = ArrayField(models.CharField(max_length=30), default=list)
cooking_method = models.TextField()
image = models.ImageField(upload_to='cuisine/')
health_benefits = models.TextField()
class Meta:
indexes = [
models.Index(fields=['name']),
models.Index(fields=['origin']),
]
class NutritionInfo(models.Model):
cuisine = models.OneToOneField(Cuisine, on_delete=models.CASCADE)
calories = models.FloatField()
protein = models.FloatField()
fat = models.FloatField()
carbohydrate = models.FloatField()
vitamin = models.JSONField(default=dict) # 存储各种维生素含量
3.2 Vue前端关键组件
- 菜品展示组件(CuisineCard.vue):
vue复制<template>
<el-card class="cuisine-card" :body-style="{ padding: '0px' }">
<img :src="cuisine.image" class="image">
<div style="padding: 14px;">
<h3>{{ cuisine.name }}</h3>
<el-tag type="success">{{ cuisine.origin }}</el-tag>
<div class="nutrition-info">
<el-progress
:percentage="caloriePercent"
:format="formatCalories"
:color="calorieColor"
/>
</div>
<el-button type="primary" @click="showDetail">查看详情</el-button>
</div>
</el-card>
</template>
<script>
export default {
props: ['cuisine'],
computed: {
caloriePercent() {
return Math.min(this.cuisine.nutrition.calories / 800 * 100, 100)
},
calorieColor() {
return this.caloriePercent > 80 ? '#f56c6c' : '#67c23a'
}
},
methods: {
formatCalories() {
return `${this.cuisine.nutrition.calories} kcal`
},
showDetail() {
this.$router.push(`/cuisine/${this.cuisine.id}`)
}
}
}
</script>
4. 健康分析模块实现
4.1 营养计算算法
python复制# flask_nutrition.py
from flask import Flask, request, jsonify
from sklearn.linear_model import LinearRegression
import joblib
import numpy as np
app = Flask(__name__)
# 加载预训练的营养模型
nutri_model = joblib.load('nutrition_model.pkl')
@app.route('/api/analyze', methods=['POST'])
def analyze_meal():
data = request.json
ingredients = data['ingredients']
# 转换为特征向量
features = np.array([
[ing['protein'], ing['fat'], ing['carb']]
for ing in ingredients
]).sum(axis=0)
# 预测健康指数
health_index = nutri_model.predict([features])[0]
return jsonify({
'total_protein': features[0],
'total_fat': features[1],
'total_carb': features[2],
'health_score': float(health_index),
'recommendation': get_recommendation(health_index)
})
def get_recommendation(score):
if score > 8: return "优秀搭配!"
elif score > 6: return "良好组合,可适当增加蔬菜"
else: return "建议调整食材比例"
4.2 Django与Flask通信
python复制# Django视图集成Flask微服务
import requests
from django.conf import settings
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['POST'])
def analyze_cuisine(request):
# 获取Django菜品数据
cuisine = get_object_or_404(Cuisine, pk=request.data['id'])
# 调用Flask微服务
flask_url = f"{settings.FLASK_SERVICE}/api/analyze"
response = requests.post(flask_url, json={
'ingredients': [
{'protein': 12, 'fat': 5, 'carb': 30}, # 示例数据
# 实际应从数据库获取
]
})
return Response({
'cuisine_info': CuisineSerializer(cuisine).data,
'nutrition_analysis': response.json()
})
5. 项目部署与优化
5.1 PyCharm开发配置
-
配置Django服务器:
- Run → Edit Configurations → Add Django Server
- 设置Host为0.0.0.0,Port为8000
- 勾选"Run browser"并设置自动打开/admin
-
Flask微服务配置:
- 新建Python配置
- Script path指向flask_app.py
- 设置环境变量FLASK_APP=flask_app.py
-
数据库工具集成:
- 安装Database插件
- 配置PostgreSQL连接
- 启用SQL方言检测
5.2 性能优化方案
- 缓存策略:
python复制# settings.py 缓存配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
# 视图缓存示例
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) # 缓存15分钟
def cuisine_list(request):
# ...
- 异步任务处理:
python复制# celery.py 配置
from celery import Celery
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
app = Celery('core')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
# 异步任务示例
@app.task(bind=True)
def generate_nutrition_report(self, cuisine_id):
cuisine = Cuisine.objects.get(pk=cuisine_id)
# 生成复杂的营养报告...
return report_data
6. 项目扩展方向
-
移动端适配:
- 开发Vue Native版本
- 添加PWA支持
- 实现扫码识别菜品功能
-
智能推荐系统:
python复制# 基于内容的推荐算法
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import linear_kernel
def build_recommendation_engine():
cuisines = Cuisine.objects.all()
corpus = [f"{c.ingredients} {c.health_benefits}" for c in cuisines]
tfidf = TfidfVectorizer(stop_words='english')
tfidf_matrix = tfidf.fit_transform(corpus)
cosine_sim = linear_kernel(tfidf_matrix, tfidf_matrix)
return cosine_sim
def recommend(cuisine_id, cosine_sim, top_n=5):
idx = cuisine_id_to_index[cuisine_id]
sim_scores = list(enumerate(cosine_sim[idx]))
sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
sim_scores = sim_scores[1:top_n+1]
cuisine_indices = [i[0] for i in sim_scores]
return Cuisine.objects.filter(id__in=indices_to_ids(cuisine_indices))
- 用户健康档案集成:
- 对接健康设备API
- 开发个性化饮食计划
- 实现健康数据可视化
在实际开发中,我发现Django的ORM与Flask的SQLAlchemy共存时需要特别注意数据库连接管理。一个实用的技巧是为Flask微服务创建单独的数据访问层,避免直接混用两种ORM。另外,Vue的组件化开发与Django模板系统的结合也需要合理规划,建议完全采用前后端分离架构,避免混合使用Django模板。
