模块化烹饪小程序开发日记 Day3:(Flask后端初始化、数据库配置与自定义日志系统搭建)

一、前言

在模块化烹饪小程序的开发体系中,后端服务是支撑前端数据交互、数据持久化以及AI解析功能的核心载体。前序开发完成了小程序前端页面的基础搭建与样式优化,本日的核心工作聚焦于Flask后端项目的完整初始化、MySQL数据库的自动化配置、全局跨域处理、自定义业务日志系统的搭建,同时完成了菜谱核心业务接口、图片静态资源服务以及AI菜谱解析接口的开发。

本次开发彻底解决了小程序前后端跨域请求报错、数据库手动创建繁琐、接口调用无日志溯源、静态大图导致小程序包体积超标等核心问题,搭建出一套可稳定迭代、可调试、可扩展的轻量化后端服务架构,为后续小程序菜谱数据的增删查改、AI智能解析、图片资源托管等功能提供了坚实的底层支撑。

二、项目技术栈与整体架构

本次后端开发采用轻量化、易部署且适配小程序开发的技术栈。整体架构采用前后端分离模式,后端专注于数据处理、数据库交互、日志记录以及AI接口对接,前端则专注于页面渲染与用户交互。

核心技术栈如下:Python Flask作为Web框架,Flask-SQLAlchemy作为ORM数据库映射工具,Flask-CORS处理跨域问题,PyMySQL作为MySQL驱动,DeepSeek AI接口提供智能解析能力。核心能力涵盖项目初始化配置、数据库自动创建与ORM映射、全局跨域放行、全接口自定义日志、图片上传与静态资源托管、菜谱数据CRUD操作以及AI结构化菜谱解析。

示例代码:项目依赖安装

bash 复制代码
pip install flask flask-sqlalchemy flask-cors pymysql requests

三、Flask项目基础初始化配置

项目初始化是后端开发的基础工作,主要完成Flask应用实例的创建、全局插件的引入、文件上传目录的自动创建以及服务运行参数的配置。统一的初始化配置能够为后续功能开发奠定稳定的基础运行环境,避免出现环境适配问题。

核心知识点包括:Flask应用实例的初始化方法、静态资源目录的自动化创建方式、服务局域网开放的具体配置。在初始化过程中,需要通过CORS组件全局开启跨域支持,同时创建用于存储上传图片的uploads目录,使用os.makedirs的exist_ok参数可以确保目录存在时不报错,实现幂等性创建。

示例代码:Flask应用初始化与跨域配置

python 复制代码
from flask import Flask, request, jsonify, send_from_directory
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
import os
import json
import requests
from datetime import datetime
import pymysql
from pymysql.constants import CLIENT

app = Flask(__name__)
CORS(app)

DB_USER = "root"
DB_PASSWORD = "your_password"
DB_HOST = "127.0.0.1"
DB_NAME = "recipe_db"

DEEPSEEK_API_KEY = "your_api_key"

app.config['UPLOAD_FOLDER'] = "uploads"
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

上述代码完成了项目基础环境的搭建工作。通过os.makedirs实现了上传目录的自动创建,无需手动新建文件夹。配置CORS(app)全局解决了前后端跨域问题,能够适配小程序前端的各类请求。统一管理数据库连接信息、AI密钥等核心配置参数,方便后续进行统一的修改和维护。

四、MySQL数据库自动化连接与模型映射

传统Flask项目开发中,数据库需要手动创建,这一操作较为繁琐且不利于项目的迁移。本次开发实现了数据库自动创建与ORM模型映射的双重机制,程序启动时会自动检测并创建数据库,同时定义菜谱数据表结构,实现数据的持久化存储。

核心知识点涵盖:PyMySQL自动建库的实现原理、SQLAlchemy ORM数据模型的定义方法、数据表的自动生成机制。通过PyMySQL连接MySQL服务器后,执行CREATE DATABASE IF NOT EXISTS语句可以安全地创建数据库。使用utf8mb4字符集能够完整支持中文和特殊符号的存储,避免出现乱码问题。

示例代码:数据库自动创建与ORM模型定义

python 复制代码
try:
    conn = pymysql.connect(
        host=DB_HOST,
        user=DB_USER,
        password=DB_PASSWORD,
        client_flag=CLIENT.MULTI_STATEMENTS
    )
    cursor = conn.cursor()
    cursor.execute(f"CREATE DATABASE IF NOT EXISTS {DB_NAME} DEFAULT CHARACTER SET utf8mb4")
    cursor.close()
    conn.close()
except Exception as e:
    print(f"数据库创建失败: {e}")

app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}/{DB_NAME}"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

class Food(db.Model):
    __tablename__ = 'foods'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(200), nullable=False)
    image_url = db.Column(db.String(500))
    desc = db.Column(db.Text)
    structured_data = db.Column(db.Text)
    create_time = db.Column(db.DateTime, default=datetime.now)

该模块实现了零手动操作的建库流程。Food模型涵盖了菜谱名称、图片地址、描述信息、结构化AI数据以及创建时间等核心字段,完全满足小程序菜谱展示、详情查询和数据存储的全部需求。

五、全局跨域处理方案

小程序前端与后端通常运行在不同的端口和域名下,这会导致浏览器默认的跨域拦截机制被触发,使得接口请求失败。本次开发采用Flask-CORS实现全局跨域放行,无需对单个接口进行单独配置,能够适配所有前后端数据交互的场景。

核心知识点包括:Flask全局跨域的配置方法、小程序跨域请求的适配原理。CORS(跨域资源共享)通过在响应头中添加Access-Control-Allow-Origin字段来告知浏览器允许跨域访问。设置为*表示允许任意域名访问,这在开发阶段非常便捷。

示例代码:全局CORS配置

python 复制代码
from flask_cors import CORS

app = Flask(__name__)
CORS(app, resources={
    r"/api/*": {
        "origins": "*",
        "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
        "allow_headers": ["Content-Type", "Authorization"]
    }
})

相较于局部跨域配置方式,全局CORS配置更加简洁高效。它可以放行小程序本地开发环境和线上环境的所有请求,彻底解决开发阶段常见的跨域报错问题,保障前后端数据交互的顺畅进行。

六、自定义全业务日志系统搭建

Flask默认的日志记录仅包含基础的请求信息,无法精准定位业务层面的问题。本次开发自主搭建了可视化业务日志系统,对所有核心接口的请求、读取、写入和异常信息进行结构化打印。日志内容包含时间戳、接口地址、请求数据、返回条数和异常提示等核心信息,极大提升了调试效率。

核心知识点包括:自定义业务日志的规范设计、接口全链路日志的记录方法、异常日志的捕获机制。通过统一的分隔线格式,可以清晰地区分不同请求的日志边界。在开发模式下使用print输出日志可以实时查看,生产环境则可以替换为专业的logging模块。

示例代码:带完整日志的接口实现

python 复制代码
@app.route('/api/food/list', methods=['GET'])
def food_list():
    print("\n" + "="*80)
    print("日志: 获取菜谱列表 /api/food/list")
    print("时间:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    
    foods = Food.query.order_by(Food.id.desc()).all()
    data = []
    for f in foods:
        img_url = f"http://127.0.0.1:5000/uploads/{os.path.basename(f.image_url)}" if f.image_url else ""
        item = {
            "id": f.id,
            "name": f.name,
            "image": img_url,
            "desc": f.desc
        }
        data.append(item)
    
    print("列表查询完成,共返回:", len(data), "条数据")
    print("="*80 + "\n")
    return jsonify({"code": 200, "data": data})

@app.route('/api/food/detail/<int:food_id>', methods=['GET'])
def food_detail(food_id):
    print("\n" + "="*80)
    print("日志: 获取菜谱详情 /api/food/detail")
    print("时间:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    print("请求ID:", food_id)
    
    food = Food.query.get(food_id)
    if not food:
        print("未找到对应菜谱,ID:", food_id)
        print("="*80 + "\n")
        return jsonify({"code": 404, "msg": "菜谱不存在"})
    
    result = {
        "id": food.id,
        "name": food.name,
        "image_url": food.image_url,
        "desc": food.desc,
        "structured_data": json.loads(food.structured_data) if food.structured_data else None,
        "create_time": food.create_time.strftime("%Y-%m-%d %H:%M:%S")
    }
    print("详情查询完成,菜谱:", food.name)
    print("="*80 + "\n")
    return jsonify({"code": 200, "data": result})

日志系统覆盖了菜谱列表、详情查询、数据新增、图片上传和AI解析等所有核心接口。统一的分隔线格式能够区分正常请求与异常请求,开发者可以清晰追溯每一次数据读写操作,快速定位参数缺失、数据查询为空、AI解析失败等开发和线上问题。

七、静态资源托管与图片上传接口实现

针对小程序代码包体积超标的问题,本次搭建了后端静态资源托管服务。将小程序中的本地大图和GIF动图迁移至后端的uploads目录,通过网络URL加载资源,大幅缩减小程序包的体积,有效解决了官方80051体积超标的报错问题。

核心知识点包括:Flask静态资源路由的配置方法、文件重命名防止覆盖的策略、小程序网络资源的适配方式。通过send_from_directory函数可以安全地从指定目录提供文件服务。使用时间戳对上传文件进行重命名,可以有效避免文件名冲突导致的资源覆盖问题。

示例代码:静态资源服务与图片上传接口

python 复制代码
@app.route('/uploads/<filename>')
def uploaded_file(filename):
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)

@app.route('/api/upload', methods=['POST'])
def upload_image():
    print("\n" + "="*80)
    print("日志: 图片上传 /api/upload")
    print("时间:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    
    if 'image' not in request.files:
        print("错误: 未选择图片")
        print("="*80 + "\n")
        return jsonify({"code": 400, "msg": "请选择图片"})
    
    file = request.files['image']
    if file.filename == '':
        print("错误: 图片文件名为空")
        print("="*80 + "\n")
        return jsonify({"code": 400, "msg": "图片不能为空"})
    
    ext = file.filename.rsplit('.', 1)[1].lower() if '.' in file.filename else 'jpg'
    filename = datetime.now().strftime("%Y%m%d%H%M%S_%f") + '.' + ext
    save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
    file.save(save_path)
    
    file_url = f"/uploads/{filename}"
    print("图片上传成功,保存路径:", save_path)
    print("访问URL:", file_url)
    print("="*80 + "\n")
    return jsonify({"code": 200, "url": file_url, "msg": "上传成功"})

通过微秒级时间戳对上传文件进行重命名,能够彻底避免同名文件被覆盖的问题。后端统一托管静态资源后,小程序端仅需保留小图标资源即可,完美适配微信小程序2MB代码包体积的限制,同时保证了图片的正常加载和展示。

八、菜谱数据读写与AI解析接口开发

本日完成了核心业务接口的开发工作,实现了菜谱数据的新增、详情查询以及AI自然语言转结构化菜谱数据的功能。同时通过详细的日志记录每一次数据写入与读取过程,保障了数据的可追溯性。

核心知识点包括:SQLAlchemy数据提交的事务机制、JSON结构化数据的存储方式、AI大模型接口的对接流程。使用db.session.add和db.session.commit完成数据的持久化操作。structured_data字段以JSON字符串形式存储,可以灵活保存步骤、食材、工具等复杂结构信息。

示例代码:菜谱新增与AI解析接口

python 复制代码
@app.route('/api/food/add', methods=['POST'])
def add_food():
    print("\n" + "="*80)
    print("日志: 新增菜谱 /api/food/add")
    print("时间:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    
    data = request.get_json()
    print("接收到的数据:", json.dumps(data, ensure_ascii=False, indent=2))
    
    if not data.get('name'):
        print("错误: 菜名不能为空")
        print("="*80 + "\n")
        return jsonify({"code": 400, "msg": "菜名不能为空"})
    
    structured_data = data.get('structured_data')
    if isinstance(structured_data, dict):
        structured_data = json.dumps(structured_data, ensure_ascii=False)
    
    food = Food(
        name=data.get('name'),
        desc=data.get('desc'),
        image_url=data.get('image_url'),
        structured_data=structured_data
    )
    db.session.add(food)
    db.session.commit()
    
    print("数据写入成功,ID:", food.id)
    print("="*80 + "\n")
    return jsonify({"code": 200, "msg": "菜谱发布成功", "id": food.id})

@app.route('/api/ai/parse', methods=['POST'])
def ai_parse_recipe():
    print("\n" + "="*80)
    print("日志: AI菜谱解析 /api/ai/parse")
    print("时间:", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    
    data = request.get_json()
    raw_text = data.get('raw_text', '')
    
    if not raw_text:
        print("错误: 待解析文本为空")
        print("="*80 + "\n")
        return jsonify({"code": 400, "msg": "请输入菜谱描述"})
    
    headers = {
        "Authorization": f"Bearer {DEEPSEEK_API_KEY}",
        "Content-Type": "application/json"
    }
    
    prompt = f"请将以下菜谱描述解析为结构化JSON,包含菜名、食材列表、步骤列表三个字段:\n{raw_text}"
    
    payload = {
        "model": "deepseek-chat",
        "messages": [{"role": "user", "content": prompt}],
        "temperature": 0.7
    }
    
    try:
        response = requests.post(
            "https://api.deepseek.com/v1/chat/completions",
            headers=headers,
            json=payload,
            timeout=30
        )
        result = response.json()
        parsed_content = result.get('choices', [{}])[0].get('message', {}).get('content', '')
        print("AI解析成功,返回内容长度:", len(parsed_content))
        print("="*80 + "\n")
        return jsonify({"code": 200, "data": parsed_content})
    except Exception as e:
        print("AI解析失败:", str(e))
        print("="*80 + "\n")
        return jsonify({"code": 500, "msg": f"AI解析失败: {str(e)}"})

该接口能够接收前端传入的结构化菜谱数据,将JSON格式的步骤、食材、工具信息存入数据库。同时对接DeepSeek AI接口,实现了自然语言菜谱的自动标准化解析功能,为小程序的动画分步烹饪功能提供了可靠的数据支撑。

九、服务启动配置与项目总结

服务启动是后端项目的最后环节,需要在启动时完成数据表的自动创建,并将服务监听在指定端口上。开启调试模式可以在代码修改后自动重载,提高开发效率。开放局域网访问则允许手机等设备在同一个网络下进行调试。

核心知识点包括:Flask应用上下文的正确使用方式、数据表自动创建的触发时机、调试模式与生产模式的区别。使用with app.app_context()可以确保在应用上下文环境中执行数据库操作。host='0.0.0.0'表示监听所有网络接口,允许外部设备访问。

示例代码:服务启动配置

python 复制代码
if __name__ == "__main__":
    with app.app_context():
        db.create_all()
    
    print("\n后端服务启动成功,监听地址: http://0.0.0.0:5000")
    print("API文档:")
    print("  GET    /api/food/list     - 获取菜谱列表")
    print("  GET    /api/food/detail   - 获取菜谱详情")
    print("  POST   /api/food/add      - 新增菜谱")
    print("  POST   /api/upload        - 上传图片")
    print("  POST   /api/ai/parse      - AI解析菜谱")
    print("日志系统已开启,可监控所有接口请求\n")
    
    app.run(host='0.0.0.0', port=5000, debug=True)

本日完成了烹饪小程序后端的全套基础架构搭建工作,实现了Flask项目的初始化配置、MySQL自动化配置、全局跨域处理、自定义业务日志系统、静态资源托管、核心业务接口与AI解析接口的开发。成功解决了小程序包体积超标、前后端跨域报错、数据库部署繁琐、接口问题无法溯源等开发痛点。

整套后端架构具备轻量化、易调试、易扩展的特点。所有业务操作均有详细的日志记录,数据读写稳定可靠,完全满足模块化烹饪小程序的业务需求,为后续的前端接口对接、功能迭代和线上部署奠定了坚实的后端基础。

十、明日开发计划

明日将继续推进项目开发,主要工作计划包括以下几个方面:

第一,完成小程序前端与后端所有接口的全面对接工作,实现菜谱列表和详情页的动态数据渲染,确保前端能够正确展示从后端获取的菜谱数据。

第二,优化静态资源的加载速度,适配小程序线上环境的HTTPS域名配置,确保图片资源能够在小程序生产环境中正常访问。

第三,完善AI菜谱解析的容错机制,增强数据解析的稳定性,处理AI接口返回格式不一致等边界情况。

第四,新增菜谱收藏功能和浏览记录业务接口,丰富小程序的核心功能模块,提升用户体验。


想要解锁更多小程序组件化封装、JSON 结构化菜谱解析、Lottie/GIF 动画适配、全栈项目落地实战干货、零基础入门避坑教程吗?
持续关注,后续将更新云端部署、跨端适配、样式统一美化、历史菜谱收藏功能等硬核内容,手把手带你吃透小程序全栈开发流程!

相关推荐
Maimai108081 小时前
Redux Toolkit 项目落地:从 slice、thunk 到可维护的前端状态管理
前端·javascript·react.js·前端框架·reactjs
格林黄1 小时前
语音电子病历python_websocket实现
开发语言·python·websocket
JavaEdge.1 小时前
07-LangChain Toolkit 实战:从工具函数到 Python Agent,再到 SQL Agent
python·sql·langchain
追梦开发者1 小时前
MongoDB 踩坑实录③:写操作、事务、聚合,踩一个就是线上事故
数据库·mongodb
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_64:从 object 到 iframe 的嵌入技术全面解析
开发语言·前端·javascript·ui·html·音视频
星梦清河1 小时前
微服务-Redis高级
数据库·redis·缓存
zhangchengjava1 小时前
Redis 连接问题完整解决报告
数据库·redis·缓存
Chase_______1 小时前
【Java杂项】为什么 b += 1 可以,但 b = b + 1 会报错?类型提升与复合赋值详解
java·开发语言·python