Django Chatterbot集成Rest API问题:请求URL时过滤菜谱被覆盖
问题分析与修复方案
核心问题
视图无状态导致数据丢失
Django视图函数是无状态的,每次用户请求都会重新执行视图内的所有代码。你定义的state和filtered_recipes是局部变量,每次请求都会被重置为初始值(state='searching'、filtered_recipes=[])。当用户第一次发送食材获取到菜谱后,视图返回asking_for_url状态,但第二次用户回复"yes/no"时,视图又重新初始化了状态和过滤结果,导致之前的菜谱数据完全丢失。重复调用
get_response覆盖过滤结果
在视图末尾,你第一次调用get_response后,如果状态变为asking_for_url,又用**同一个用户输入(食材内容)**再次调用get_response。此时第二次调用会进入asking_for_url分支的else逻辑,重新提取食材并过滤菜谱,直接覆盖了之前正确的filtered_recipes,导致后续无法拿到目标菜谱。
修复方案
方案1:使用Django会话(Session)保存状态与过滤结果(彻底解决)
Django的Session可以在用户的多次请求之间保存数据,是处理这类交互场景的标准方式:
from django.http import JsonResponse from django.forms.models import model_to_dict # 如果菜谱是ORM模型,用这个转字典 def recipe_chatbot_view(request): if request.method == 'POST': # 从会话读取状态和过滤结果,默认值为初始状态 state = request.session.get('state', 'searching') # 如果菜谱是ORM对象,保存序列化后的字典;如果是普通字典直接读取 filtered_recipes = request.session.get('filtered_recipes', []) message = request.POST.get('message', '').strip() def get_response(message, state, filtered_recipes): if state == 'searching': ingredients = extract_ingredients(message) filtered_recipes = filter_recipes_by_ingredients(ingredients) # 把ORM对象转成可序列化的字典(如果用的是普通字典可省略这步) filtered_recipes = [model_to_dict(recipe) for recipe in filtered_recipes] if filtered_recipes: recipe = filtered_recipes[0] state = 'asking_for_url' return ( JsonResponse({ 'message': f"{recipe['description']} 需要我提供这道菜的做法链接吗?" }), state, filtered_recipes ) else: state = 'no_recipes_found' return ( JsonResponse({ 'message': "抱歉,目前没有使用这些食材的菜谱。" }), state, filtered_recipes ) elif state == 'asking_for_url': if 'yes' in message.lower(): if filtered_recipes: recipe = filtered_recipes[0] state = 'recipe_url_provided' return ( JsonResponse({ 'message': f"这是菜谱链接:{recipe['url']} \n 祝你烹饪愉快!" }), state, filtered_recipes ) else: # 处理会话数据丢失的异常情况 state = 'searching' return ( JsonResponse({ 'message': "抱歉,我丢失了之前的菜谱信息,请重新输入食材。" }), state, [] ) elif 'no' in message.lower(): state = 'searching' return ( JsonResponse({ 'message': "好的,有其他需求随时告诉我。" }), state, [] ) else: # 用户输入不是yes/no,重新处理食材 ingredients = extract_ingredients(message) filtered_recipes = filter_recipes_by_ingredients(ingredients) filtered_recipes = [model_to_dict(recipe) for recipe in filtered_recipes] if filtered_recipes: recipe = filtered_recipes[0] state = 'asking_for_url' return ( JsonResponse({ 'message': f"{recipe['description']} 需要我提供这道菜的做法链接吗?" }), state, filtered_recipes ) else: state = 'no_recipes_found' return ( JsonResponse({ 'message': "抱歉,目前没有使用这些食材的菜谱。" }), state, filtered_recipes ) elif state == 'recipe_url_provided': state = 'searching' return ( JsonResponse({ 'message': "好的,有其他需求随时告诉我,祝你烹饪开心!" }), state, [] ) # 仅调用一次get_response,避免重复处理 response, state, filtered_recipes = get_response(message, state, filtered_recipes) # 将更新后的状态和过滤结果保存到会话 request.session['state'] = state request.session['filtered_recipes'] = filtered_recipes return response
方案2:临时移除重复调用代码(仅解决单次请求内的覆盖问题)
如果暂时不处理跨请求的状态保存,先删除视图末尾的重复调用代码,避免单次请求内覆盖过滤结果:
# 删掉以下两行代码 # if state == 'asking_for_url': # response, state, filtered_recipes = get_response(message, state, filtered_recipes)
注意:这个方案只能解决单次请求内的过滤结果覆盖问题,无法解决跨请求的状态丢失,用户第二次回复时依然会丢失之前的菜谱数据。
额外注意事项
- 如果你的菜谱是Django ORM模型对象,不能直接保存到Session,需要用
model_to_dict或自定义序列化方式转成可序列化的字典。 - 确保项目已启用Django Session中间件(默认是启用的),并正确配置了
SESSION_ENGINE。
内容的提问来源于stack exchange,提问作者Nifise Oguntoye
相关产品推荐
相关产品推荐

