鞍山市网站建设_网站建设公司_网站备案_seo优化
2025/12/19 17:44:23 网站建设 项目流程

食鲜配·智厨

这个项目属于哪个课程 https://edu.cnblogs.com/campus/fzu/2025DataCollectionandFusiontechnology
组名 风雨无组
项目名字及简介 食鲜配·智厨是一个基于Python 3.7+和Django 2.0.7的智能电商菜谱一体化平台,实现了"购物-菜谱-健康"的完整闭环,为用户提供"买什么-怎么做-吃得健康"一站式解决方案。
项目logo 341db5339e9873a3c2392516989b27d6_720
团队成员学号 102302101、102302102、102302103、102302104、102302105、102302106、102302109、102302110
项目目标 实现网页端多源异构数据采集,构建用户画像并完成食材与菜谱的智能推荐,实现 AI 分析与 Web 应用展示,形成完整的数据采集与融合闭环。
其他参考文献 https://github.com/CRIPAC-DIG/SR-GNN 、https://docs.djangoproject.com/
gitee链接 https://gitee.com/ding41/buy-menu

系统架构设计

系统整体采用 B/S 架构,构建如下闭环流程:
多源数据采集 → 数据分析与融合 → 推荐算法 → Web系统展示 → 用户交互 → 行为反馈

技术栈

  • 后端: Django 2.7, Python 3.11
  • 数据库: SQLite
  • 前端: HTML, CSS, JavaScript, jQuery
  • 其他: Pillow (图片处理), django-haystack (搜索)

核心功能设计与实现

后台管理系统

  • 商品全生命周期管理
  • 菜谱管理与食材绑定
  • 用户行为数据可视化

前台核心功能

商品浏览与购物车

  • 分类浏览、关键词搜索
  • 分量与处理方式选择
  • 购物车实时价格更新
    菜谱推荐与双向推荐算法
  • 商品 → 菜谱推荐:基于商品标签匹配菜谱食材
  • 菜谱 → 商品推荐:基于菜谱所需食材匹配商品
  • 支持“一键加购”
    AI 智能分析与个性化模块
  • 食材搭配合理性分析
  • 健康饮食偏好设置(低糖/低盐等)
  • AI 助手提供烹饪与处理建议

个人工作(核心功能实现)

1. 用户系统后端

支持用户注册、登录、个人信息管理。使用了Django的认证系统,并添加了自定义装饰器来保护用户相关页面。

用户注册代码实现

def register_handle(request):username = request.POST.get('user_name')password = request.POST.get('pwd')confirm_pwd = request.POST.get('confirm_pwd')email = request.POST.get('email')# 判断两次密码一致性if password != confirm_pwd:return redirect('/user/register/')# 密码加密s1 = sha1()s1.update(password.encode('utf8'))encrypted_pwd = s1.hexdigest()# 创建对象UserInfo.objects.create(uname=username, upwd=encrypted_pwd, uemail=email)# 注册成功context = {'title': '用户登陆','username': username,}return render(request, 'df_user/login.html', context)def register_exist(request):username = request.GET.get('uname')count = UserInfo.objects.filter(uname=username).count()return JsonResponse({'count': count})

用户登录代码实现

def login_handle(request):uname = request.POST.get('username')upwd = request.POST.get('pwd')jizhu = request.POST.get('jizhu', 0)users = UserInfo.objects.filter(uname=uname)if len(users) == 1:s1 = sha1()s1.update(upwd.encode('utf8'))if s1.hexdigest() == users[0].upwd:url = request.COOKIES.get('url', '/')red = HttpResponseRedirect(url)# 是否勾选记住用户名,设置cookieif jizhu != 0:red.set_cookie('uname', uname)else:red.set_cookie('uname', '', max_age=-1)request.session['user_id'] = users[0].idrequest.session['user_name'] = unamereturn redelse:# 密码错误处理context = {'title': '用户名登陆','error_name': 0,'error_pwd': 1,'uname': uname,'upwd': upwd,}return render(request, 'df_user/login.html', context)else:# 用户名不存在处理context = {'title': '用户名登陆','error_name': 1,'error_pwd': 0,'uname': uname,'upwd': upwd,}return render(request, 'df_user/login.html', context)

登录装饰器

def login(func):def login_fun(request, *args, **kwargs):if request.session.has_key('user_id'):return func(request, *args, **kwargs)else:red = HttpResponseRedirect('/user/login/')red.set_cookie('url', request.get_full_path())return redreturn login_fun

展示

登录界面
QQ_1766135102807
注册界面
QQ_1766135110970

2.AI食材搭配分析功能

项目集成了先进的AI功能,通过调用Deepseek大语言模型API来分析用户购物车中食材的搭配合理性,为用户提供智能化的营养建议和健康指导。

实现原理和核心代码

AI分析模块的核心位于 apps/utils/ai_analyzer.py

  1. FoodAnalyzer类:核心分析器类
    class FoodAnalyzer:def __init__(self, api_key: str):self.api_key = api_keyself.api_url = "https://api.deepseek.com/v1/chat/completions"self.headers = {"Content-Type": "application/json","Authorization": f"Bearer {api_key}"}
    

__init__方法初始化分析器实例,设置API端点URL为Deepseek的chat completions接口,配置HTTP请求头,包含JSON内容类型和Bearer认证

  1. API通信方法

    def _call_api(self, messages: List[Dict[str, str]], model: str = "deepseek-chat") -> str:try:data = {"model": model,"messages": messages,"temperature": AI_ANALYSIS_CONFIG['temperature'],"max_tokens": AI_ANALYSIS_CONFIG['max_tokens']}response = requests.post(self.api_url, headers=self.headers, json=data, timeout=API_TIMEOUT)response.raise_for_status()result = response.json()return result["choices"][0]["message"]["content"]except requests.exceptions.RequestException as e:logger.error(f"API调用失败: {e}")return "抱歉,AI分析服务暂时不可用,请稍后再试。"except KeyError as e:logger.error(f"API响应格式错误: {e}")return "抱歉,AI分析服务出现异常,请稍后再试。"except Exception as e:logger.error(f"未知错误: {e}")return "抱歉,分析过程中出现错误,请稍后再试。"
    
    • 构建API请求数据,包含模型参数和对话消息
    • 使用requests库发送POST请求,设置超时时间
    • 解析JSON响应,提取AI的回复内容
    • 多层异常处理:网络错误、响应格式错误、未知异常
    • 返回用户友好的错误提示信息
  2. 数据预处理

    # 在analyze_food_combination方法中
    food_list = []
    for item in cart_items:food_name = item.get('goods_name', '')quantity = item.get('count', 1)category = item.get('category', '')if food_name:food_list.append(f"{food_name}({quantity}个) - {category}")
    food_str = "\n".join(food_list)
    

通过遍历购物车商品列表,提取商品名称、数量和类别,然后格式化每个商品为"名称(数量个) - 类别"的字符串
通过使用换行符连接所有商品,形成完整的食材清单

API调用流程

完整的API调用流程如下:

  1. 数据准备阶段
    if not cart_items:return {"success": False, "message": "购物车中没有商品", "analysis": None}
    # 提取商品信息...
    

首先检查购物车是否为空,返回错误信息,然后提取每个商品的名称、数量、类别信息

  1. 提示词构建
    定义系统角色为营养师专家,用户消息包含具体的分析要求和食材清单
    prompt = f"""
    作为一名专业的营养师和食品安全专家,请分析以下购物车中的食材搭配是否合理:
    购物车商品清单:
    {food_str}
    请从以下几个维度进行分析:
    1. 营养搭配分析...
    2. 食品安全评估...
    3. 适宜人群分析...
    4. 健康建议...
    """
    messages = [{"role": "system", "content": "你是一位专业的营养师和食品安全专家,擅长分析食材搭配的营养价值和安全性。"},{"role": "user", "content": prompt}
    ]
    
  2. API请求执行
    调用内部的_call_api方法执行API请求,返回结构化的结果字典,包含成功状态、分析内容和统计信息
    analysis_result = self._call_api(messages)
    return {"success": True,"message": "分析完成","analysis": analysis_result,"food_count": len(cart_items),"food_list": food_list
    }
    

分析维度详解

AI分析涵盖四个主要维度,每个维度都有具体的分析内容:

  1. 营养搭配分析

    • 评估宏营养素(蛋白质、碳水化合物、脂肪)比例
    • 检查微营养素(维生素、矿物质)是否充足
    • 分析膳食纤维和抗氧化物质含量
    • 识别营养过剩或缺乏的风险
  2. 食品安全评估

    • 检查食材间的生化反应(如维生素C与铁的协同作用)
    • 识别潜在的食物相克(如某些中药材与食物)
    • 评估储存安全(如易腐烂食材的保存建议)
    • 提供烹饪安全指导(如高温烹调的注意事项)
  3. 适宜人群分析

    • 识别适合的消费人群(如孕妇、儿童、老年人)
    • 指出不适宜人群(如糖尿病患者、肾病患者)
    • 考虑特殊饮食需求(如素食、宗教饮食限制)
  4. 健康建议

    • 推荐补充食材以完善营养结构
    • 建议调整食材比例或替换选项
    • 提供烹饪方法和食用建议
    • 生成1-2个简单的食谱推荐

个性化建议功能

get_personalized_advice() 方法提供基于用户档案的定制化建议:

  1. 用户档案
    从前端GET参数获取用户档案信息,将数据库中的健康偏好强制添加到用户档案中

    user_profile = request.GET.dict()
    if health_pref:user_profile['health_preference'] = health_pref
    
  2. 针对性分析
    检查用户是否有特殊的健康关注点,在提示词中添加重要标记,要求AI重点关注这些健康问题

    health_pref_str = ""  
    if user_profile:pref = user_profile.get('health_preference', '')if pref:health_pref_str = f"\n🔴 【重要】用户特别健康关注:{pref} (请在分析时重点针对这些点进行警告或推荐)"
    
  3. 定制化输出

    prompt = f"""
    基于以下购物车内容和用户信息,提供个性化的营养建议:
    购物车商品:
    {food_str}
    用户信息:
    年龄:{user_profile.get('age', '未知')}
    性别:{user_profile.get('gender', '未知')}
    健康状况:{user_profile.get('health_status', '无特殊疾病')}
    {health_pref_str}
    """
    

配置和调试模式

  1. 配置文件 (config.py):

    AI_ANALYSIS_CONFIG = {'max_food_items': 20,     # 最多分析商品数量'temperature': 0.7,       # AI创造性程度 (0-1)'max_tokens': 2000,       # 最大回复长度
    }
    DEBUG_AI = False  # 调试模式开关
    
  2. 调试模式

    def get_analyzer() -> FoodAnalyzer:if DEBUG_AI or not DEEPSEEK_API_KEY or DEEPSEEK_API_KEY == "sk-your-deepseek-api-key-here":return MockFoodAnalyzer()return FoodAnalyzer(DEEPSEEK_API_KEY)
    

先检查调试模式或API密钥是否有效,如果条件满足,返回模拟分析器,否则返回真实的AI分析器实例

  1. 错误处理
    • API调用失败时返回友好提示
    • 记录详细错误日志便于调试
    • 保证系统在API不可用时仍能正常运行

展示

QQ_1766135292220

菜谱与食材的联动

数据模型设计

菜谱与食材的联动首先需要良好的数据模型设计。我通过三个核心模型来实现这一功能:

1. Recipe模型 - 食谱信息

QQ_1766136458470

class Recipe(models.Model):"""食谱"""cid = models.ForeignKey(RecipeType, on_delete=models.CASCADE, verbose_name="分类", db_column='cid')title = models.CharField(max_length=100, verbose_name="食谱名称")thumb = models.CharField(max_length=100, blank=True, null=True, verbose_name="缩略图")videourl = models.CharField(max_length=200, blank=True, null=True, verbose_name="视频链接")desc = models.CharField(max_length=500, blank=True, null=True, verbose_name="描述")yl = models.CharField(max_length=500, blank=True, null=True, verbose_name="用料")fl = models.CharField(max_length=500, blank=True, null=True, verbose_name="分量")steptext = models.TextField(blank=True, null=True, verbose_name="步骤文字")steppic = models.TextField(blank=True, null=True, verbose_name="步骤图片")grade = models.FloatField(default=0, verbose_name="评分")class Meta:db_table = 'df_recipe'verbose_name = "食谱"verbose_name_plural = verbose_namedef __str__(self):return self.title

2. GoodsInfo模型 - 商品(食材)信息

QQ_1766136584338

class GoodsInfo(models.Model):# 具体商品信息isDelete = models.BooleanField(default=False)  # 逻辑删除gtitle = models.CharField(max_length=20, verbose_name="商品名称", unique=True)gpic = models.ImageField(verbose_name='商品图片', upload_to='df_goods/image/%Y/%m', null=True, blank=True)gprice = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="商品价格")gunit = models.CharField(max_length=20, default='500g', verbose_name="单位重量")gclick = models.IntegerField(verbose_name="点击量", default=0, null=False)gjianjie = models.CharField(max_length=200, verbose_name="简介")gkucun = models.IntegerField(verbose_name="库存", default=0)gcontent = HTMLField(max_length=200, verbose_name="详情")gtype = models.ForeignKey(TypeInfo, on_delete=models.CASCADE, verbose_name="分类")class Meta:verbose_name = "商品"verbose_name_plural = verbose_namedef __str__(self):return self.gtitle

3. RecipeGoods模型 - 关联表

QQ_1766136429350

这是实现联动功能的核心模型:

class RecipeGoods(models.Model):"""食谱与商品关联表"""recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, verbose_name="食谱", related_name='recipe_goods')goods = models.ForeignKey(GoodsInfo, on_delete=models.CASCADE, verbose_name="商品", related_name='goods_recipes')amount = models.CharField(max_length=50, blank=True, null=True, verbose_name="用量说明")class Meta:db_table = 'df_recipe_goods'verbose_name = "食谱食材"verbose_name_plural = verbose_nameunique_together = ('recipe', 'goods')  # 防止重复关联def __str__(self):return f"{self.recipe.title} - {self.goods.gtitle}"

通过RecipeGoods模型,我建立了菜谱和食材之间的多对多关系,并记录了每个食材在菜谱中的用量。

后端视图实现

1. 商品详情页视图

在商品详情页,我需要显示与该食材相关的所有菜谱:

def detail(request, gid):"""商品详情页视图"""try:goods = GoodsInfo.objects.get(pk=int(gid))except GoodsInfo.DoesNotExist:from django.shortcuts import redirectreturn redirect('df_goods:index')goods.gclick += 1goods.save()news = goods.gtype.goodsinfo_set.order_by('-id')[0:2]# 获取与该商品相关的所有食谱recipe_goods = RecipeGoods.objects.filter(goods_id=gid).select_related('recipe')recipes = [rg.recipe for rg in recipe_goods]context = {'title': goods.gtype.ttitle,'guest_cart': 1 if 'user_id' in request.session else 0,'cart_num': cart_count(request),'goods': goods,'news': news,'id': gid,'recipes': recipes,  # 传递食谱列表到模板}response = render(request, 'df_goods/detail.html', context)# ... 处理浏览记录的代码return response

2. 食谱详情API

提供获取食谱详细信息和关联食材的API接口:

def recipe_detail(request, recipe_id):"""获取食谱详情和关联商品的API"""try:recipe = Recipe.objects.get(pk=recipe_id)# 获取食谱关联的所有商品recipe_goods = RecipeGoods.objects.filter(recipe_id=recipe_id).select_related('goods')goods_list = []for rg in recipe_goods:goods_list.append({'id': rg.goods.id,'title': rg.goods.gtitle,'price': str(rg.goods.gprice),'pic': str(rg.goods.gpic) if rg.goods.gpic else '','unit': rg.goods.gunit,'kucun': rg.goods.gkucun,'amount': rg.amount or '',  # 用量说明})# 解析步骤steps = []if recipe.steptext:step_texts = recipe.steptext.split('#')step_pics = recipe.steppic.split('#') if recipe.steppic else []for i, text in enumerate(step_texts):if text.strip():steps.append({'text': text.strip(),'pic': step_pics[i] if i < len(step_pics) else ''})# 解析用料ingredients = []if recipe.yl and recipe.fl:yl_list = recipe.yl.split('#')fl_list = recipe.fl.split('#')for i, yl in enumerate(yl_list):if yl.strip():ingredients.append({'name': yl.strip(),'amount': fl_list[i].strip() if i < len(fl_list) else ''})data = {'success': True,'recipe': {'id': recipe.id,'title': recipe.title,'thumb': recipe.thumb or '','desc': recipe.desc or '','videourl': recipe.videourl or '','grade': recipe.grade,'ingredients': ingredients,'steps': steps,},'goods': goods_list,}return JsonResponse(data)except Recipe.DoesNotExist:return JsonResponse({'success': False, 'message': '食谱不存在'})except Exception as e:return JsonResponse({'success': False, 'message': str(e)})

URL配置

urls.py中配置相关的路由:

urlpatterns = [url('^$', views.index, name="index"),url('^list(\d+)_(\d+)_(\d+)/$', views.good_list, name="good_list"),url('^(\d+)/$', views.detail, name="detail"),url(r'^search/', views.ordinary_search, name="ordinary_search"),url(r'^recipe/(\d+)/$', views.recipe_detail, name="recipe_detail"),  # 食谱详情API
]

前端实现

1. 商品详情页模板

在商品详情页左侧添加食谱推荐区域:

<!-- 食谱推荐 -->
{% if recipes %}
<div class="recipe_recommend"><h3>食谱推荐</h3><ul class="recipe_list">{% for recipe in recipes %}<li class="recipe_item" data-recipe-id="{{ recipe.id }}"><div class="recipe_thumb"><img src="/{{ recipe.thumb }}" alt="{{ recipe.title }}"></div><div class="recipe_info"><h4>{{ recipe.title }}</h4><span class="recipe_grade">评分: {{ recipe.grade }}</span></div></li>{% endfor %}</ul>
</div>
{% endif %}

2. 动态标签页

在右侧添加用于显示食谱详情的标签页:

<div class="tab_content" id="tabContent"><!-- 商品介绍 --><div class="tab_pane active" id="goodsPane"><dl><dt>商品详情:</dt><dd>{{ goods.gcontent|safe }}</dd></dl></div><!-- 食谱介绍 --><div class="tab_pane" id="recipePane" style="display:none;"><div id="recipeContent"><p class="recipe_placeholder">请从左侧选择一个食谱查看详情</p></div></div><!-- 食材用量 --><div class="tab_pane" id="ingredientPane" style="display:none;"><div id="ingredientContent"><p class="ingredient_placeholder">请从左侧选择一个食谱查看食材</p></div></div>
</div>

JavaScript交互实现

1. 食谱点击事件

$(document).ready(function(){// ... 其他初始化代码// 点击食谱$('.recipe_item').click(function() {var recipeId = $(this).data('recipe-id');$('.recipe_item').removeClass('active');$(this).addClass('active');loadRecipeDetail(recipeId);});// Tab切换$('#detailTabs li').click(function() {var tab = $(this).data('tab');$('#detailTabs li').removeClass('active');$(this).addClass('active');$('.tab_pane').hide();if (tab === 'goods') {$('#goodsPane').show();} else if (tab === 'comment') {$('#commentPane').show();} else if (tab === 'recipe') {$('#recipePane').show();} else if (tab === 'ingredient') {$('#ingredientPane').show();}});
});

2. 加载食谱详情

// 加载食谱详情
function loadRecipeDetail(recipeId) {$.ajax({url: '/recipe/' + recipeId + '/',type: 'GET',dataType: 'json',success: function(data) {if (data.success) {currentRecipeData = data;renderRecipeContent(data);// 切换到食谱介绍tabupdateTabsForRecipe();$('#detailTabs li[data-tab="recipe"]').click();} else {alert(data.message || '加载失败');}},error: function() {alert('网络错误');}});
}// 更新tabs显示食谱相关选项
function updateTabsForRecipe() {var tabs = $('#detailTabs');if (tabs.find('[data-tab="recipe"]').length === 0) {tabs.append('<li data-tab="recipe">食谱介绍</li>');tabs.append('<li data-tab="ingredient">食材用量</li>');// 重新绑定点击事件tabs.find('li').off('click').on('click', function() {var tab = $(this).data('tab');$('#detailTabs li').removeClass('active');$(this).addClass('active');$('.tab_pane').hide();$('#' + tab + 'Pane').show();});}
}

3. 渲染食谱内容

// 渲染食谱内容
function renderRecipeContent(data) {var recipe = data.recipe;var goods = data.goods;// 渲染食谱介绍var recipeHtml = '<div class="recipe_detail">';recipeHtml += '<h3>' + recipe.title + '</h3>';if (recipe.thumb) {recipeHtml += '<div class="recipe_main_img"><img src="/' + recipe.thumb + '" alt=""></div>';}if (recipe.desc) {recipeHtml += '<p class="recipe_desc">' + recipe.desc + '</p>';}if (recipe.videourl) {recipeHtml += '<p><a href="' + recipe.videourl + '" target="_blank" class="video_link">📺 观看视频教程</a></p>';}// 步骤if (recipe.steps && recipe.steps.length > 0) {recipeHtml += '<div class="recipe_steps"><h4>制作步骤</h4><ol>';recipe.steps.forEach(function(step, index) {recipeHtml += '<li class="step_item">';recipeHtml += '<div class="step_text">' + step.text + '</div>';if (step.pic) {recipeHtml += '<div class="step_pic"><img src="/' + step.pic + '" alt="步骤' + (index+1) + '"></div>';}recipeHtml += '</li>';});recipeHtml += '</ol></div>';}recipeHtml += '</div>';$('#recipeContent').html(recipeHtml);// 渲染食材用量var ingredientHtml = '<div class="ingredient_detail">';ingredientHtml += '<h3>食材用量</h3>';// 关联商品if (goods && goods.length > 0) {ingredientHtml += '<div class="related_goods"><h4>可购买食材</h4><ul class="goods_grid">';goods.forEach(function(g) {ingredientHtml += '<li class="goods_card" data-goods=\'' + JSON.stringify(g) + '\'>';ingredientHtml += '<div class="goods_img"><img src="/media/' + g.pic + '" alt=""></div>';ingredientHtml += '<div class="goods_name">' + g.title + '</div>';ingredientHtml += '<div class="goods_price">¥' + g.price + '/' + g.unit + '</div>';if (g.amount) {ingredientHtml += '<div class="goods_amount">建议用量: ' + g.amount + '</div>';}ingredientHtml += '<button class="add_to_cart_btn">加入购物车</button>';ingredientHtml += '</li>';});ingredientHtml += '</ul></div>';}ingredientHtml += '</div>';$('#ingredientContent').html(ingredientHtml);// 绑定商品点击事件$('.goods_card .add_to_cart_btn').click(function(e) {e.stopPropagation();var goodsData = $(this).closest('.goods_card').data('goods');showIngredientModal(goodsData);});
}

展示

QQ_1766136361328
QQ_1766136372431

个性化界面

用户数据模型设计

QQ_1766136924669

个性化功能的核心在于用户数据的收集和分析。我们通过扩展Django的用户模型来实现个性化数据存储:

1. 扩展用户模型

class UserInfo(models.Model):uname = models.CharField(max_length=20, verbose_name="用户名", unique=True)upwd = models.CharField(max_length=40, verbose_name="用户密码", blank=False)uemail = models.EmailField(verbose_name="邮箱", unique=True)ushou = models.CharField(max_length=20, default="", verbose_name="收货地址")uaddress = models.CharField(max_length=100, default="", verbose_name="地址")uyoubian = models.CharField(max_length=6, default="", verbose_name="邮编")uphone = models.CharField(max_length=11, default="", verbose_name="手机号")# === 个性化字段 ===# 用于存储健康偏好,例如 "低糖,低胆固醇"health_preference = models.CharField(max_length=255, default='', verbose_name='健康偏好', blank=True) class Meta:verbose_name = "用户信息"verbose_name_plural = verbose_namedef __str__(self):return self.uname

2. 用户浏览记录模型

class GoodsBrowser(models.Model):user = models.ForeignKey(UserInfo, on_delete=models.CASCADE, verbose_name="用户ID")good = models.ForeignKey(GoodsInfo, on_delete=models.CASCADE, verbose_name="商品ID")browser_time = models.DateTimeField(default=datetime.now, verbose_name="浏览时间")class Meta:verbose_name = "用户浏览记录"verbose_name_plural = verbose_namedef __str__(self):return "{0}浏览记录{1}".format(self.user.uname, self.good.gtitle)

健康偏好设置功能

1. 偏好设置界面设计

健康偏好是用户个性化体验的核心。我们设计了一个友好的弹窗界面,让用户轻松设置自己的健康关注点:

<!-- 健康偏好弹窗组件 -->
<div id="preference_modal" class="pref-modal" style="display: none;"><div class="pref-content"><div class="pref-header"><h3>🍅 个性化饮食设置</h3><p>请问您关注食物的什么方面?AI将为您提供定制建议。</p></div><div class="pref-body"><div class="tag-container"><span class="pref-tag" data-value="低糖">🍬 低糖</span><span class="pref-tag" data-value="低胆固醇">🥩 低胆固醇</span><span class="pref-tag" data-value="低盐">🧂 低盐</span><span class="pref-tag" data-value="高蛋白">💪 高蛋白</span><span class="pref-tag" data-value="低卡路里">🥗 低卡路里</span><span class="pref-tag" data-value="素食">🥬 素食</span><span class="pref-tag" data-value="无麸质">🌾 无麸质</span></div><input type="hidden" id="selected_prefs" value=""></div><div class="pref-footer"><button onclick="savePreferences()" class="save-btn">确认并保存</button><a href="javascript:closeModal()" class="skip-link">暂时跳过</a></div></div>
</div>

2. 弹窗样式设计

.pref-modal {position: fixed; top: 0; left: 0; width: 100%; height: 100%;background: rgba(0,0,0,0.6); z-index: 9999;display: flex; justify-content: center; align-items: center;backdrop-filter: blur(2px);
}.pref-content {background: white; width: 420px; border-radius: 16px; padding: 30px;box-shadow: 0 10px 30px rgba(0,0,0,0.2); text-align: center;animation: modalFadeIn 0.3s ease;
}.pref-tag {padding: 8px 18px; border: 1px solid #eee; border-radius: 25px; cursor: pointer;color: #555; transition: all 0.2s; background: #f9f9f9; font-size: 14px;
}.pref-tag.active {background: linear-gradient(135deg, #ff8800 0%, #ff5500 100%);color: white; border-color: transparent;box-shadow: 0 4px 10px rgba(255, 85, 0, 0.3);
}

3. 偏好设置后端逻辑

@user_decorator.login
def save_health_preference(request):"""保存用户的健康偏好"""if request.method == 'POST':preferences = request.POST.get('preferences', '')uid = request.session.get('user_id')try:user = UserInfo.objects.get(id=uid)user.health_preference = preferencesuser.save()return JsonResponse({'success': True, 'message': '偏好设置成功'})except Exception as e:return JsonResponse({'success': False, 'message': str(e)})return JsonResponse({'success': False, 'message': '请求方法错误'})

4. 弹窗交互逻辑

$(function() {// 检查是否已设置偏好var currentPref = "{{ user_info.health_preference|default:'' }}";// 如果偏好为空,显示弹窗if (currentPref === "") {setTimeout(function(){$('#preference_modal').fadeIn();}, 500);}// 标签点击交互$('.pref-tag').click(function() {$(this).toggleClass('active');updateSelected();});
});function updateSelected() {var selected = [];$('.pref-tag.active').each(function() {selected.push($(this).data('value'));});$('#selected_prefs').val(selected.join(','));
}function savePreferences() {var prefs = $('#selected_prefs').val();if(!prefs) {alert("请至少选择一项,或者点击跳过");return;}$.ajax({url: '{% url "df_user:save_preference" %}',type: 'POST',data: {'preferences': prefs,'csrfmiddlewaretoken': '{{ csrf_token }}'},success: function(res) {if(res.success) {alert("✅ 设置成功!AI将为您关注这些健康指标。");closeModal();setTimeout(function(){ location.reload(); }, 500);} else {alert("保存失败:" + res.message);}},error: function() {alert("网络请求错误,请稍后再试");}});
}

QQ_1766137003478

5部署项目到华为云服务器

连接华为云服务器

a0043429fbeae2c1a86f3ab934b82db2

安装宝塔linux面板

wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh

安装成功后会出现一下信息:可以看到外网和内网的访问面板,我们在Windows端使用外网面板地址即可访问,然后输入对应的username和password。
dc664119bdf8e09985098c00d92fca35
根据终端的提示放通华为云的端口
574e533a0d02befb2ce122f95af3152d

安装项目对应的python版本

sudo apt update
sudo apt install software-properties-common# 使用Apt-Get安装Python 3.11
# 打开系统上的终端,然后为系统配置Deadsnakes PPA。
sudo add-apt-repository ppa:deadsnakes/ppa
# 在Ubuntu系统上添加ppa后,更新apt缓存并在Ubuntu上安装Python 3.11
sudo apt update
sudo apt install python3.11
# 等待安装完成。通过执行以下命令检查Python版本:
python3.11 -V# 至此,Python 3.11已安装在Ubuntu系统上并可以使用。
创建软链接:
# 重新指定python为python3的软连接
sudo ln -s /usr/bin/python3.11 /usr/bin/python查看最后是否安装成功:
pyhton -V

5ddd31143c45a7f2a9db5db265cc13df

安装虚拟环境(防止意外发生导致系统奔溃):

apt-get update
apt-get upgrade
pip install virtualenvcd ~
cd /home
virtualenv django #在django文件夹下创建虚拟环境
cd django
source bin/activate  #激活虚拟环境

如下图左端有(django)标识,则表示创建成功
cabdd3bf8f297c7653c531c8030f425f

将Django项目文件上传至华为云服务器

f3b6143dcfd1e9fd175a92ae5464ecbe

修改上传到服务器的django文件中的seeting.py文件

使得其他ip也能够访问Django项目
7de2437432223f66a2de1c109266c2cf

安装Django项目的依赖库

将项目的依赖库整理成如下文档
6195f3b75d223dfaef0f3d92b4920eb2
读取安装依赖库

pip install -Ur requirements.txt

18de4d673a5fd73412a4842de452fcbc

启动Django项目

前台运行(关闭远程后程序会结束运行)

python manage.py runserver 0.0.0.0:8080

后台运行(关闭远程后程序不会结束运行)

nohup python manage.py runserver 0.0.0.0:8080 &

运行结果如下
273637c9ab43e9e4ffc747f0f2f7a5c8
查看服务器IP
af720f4f7d7e1af8b3e6e4f69337f611

21d6ec62c0df2deac65c5a7297bf32cf
运行对应的url即可
结果如下
706e66554e2f29283fc6113ec1611cae

注意事项

关闭防火墙
记得进入宝塔界面,把服务器防火墙关掉,这样外界才可以访问这个端口的数据
427cbf4e6953c01c2ef01d9e9ab4af1c

个人心得

  1. 后端开发能力的深化:通过主导用户系统和AI食材搭配分析功能的开发,我对Django框架的理解从基础应用提升到了实战深度。例如在用户认证模块中,不仅熟练运用了Django自带的认证系统,还通过自定义装饰器实现了页面权限控制,深入理解了session与cookie的协同工作机制,解决了用户登录状态保持、登录后跳转原页面等实际问题。
  2. AI接口集成与异常处理思维的建立:在对接Deepseek大语言模型API时,我学会了规范的接口调用流程,包括请求头配置、参数构造、响应解析等。更重要的是,通过设计多层异常处理机制,覆盖了网络错误、响应格式错误、未知异常等场景,确保了系统在AI服务不稳定时仍能正常运行,培养了“防御性编程”的思维。
  3. 明确分工与责任意识的强化:作为团队的一员,我负责核心功能的后端实现与部分前端交互逻辑开发。在项目推进过程中,通过与前端成员明确数据交互格式,与其他后端成员协调数据库模型设计,确保了各模块的兼容对接。这让我深刻认识到,清晰的分工和强烈的责任意识是团队项目顺利推进的关键。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询