订单后台管理系统-day07菜品模块

添加和编辑菜品模块

文件上传

  • 菜品的添加需要使用到富文本编辑器

  • 添加菜品时需要上传图片,所以我们需要配置文件上传的操作,设定全局变量

python 复制代码
 UPLOAD = {
        # 定义可上传的图片类型
        'ext': ['jpg', 'gif', 'bmp', 'jpeg', 'png'],
        # 普通文件保存路径
        'prefix_path': 'web/static/upload/',
        # 富文本图片路径
        'prefix_url': 'static/upload/'
    }
  • utils/views.py全局工具文件中
python 复制代码
@utils_bp.route('/upload_pic', methods=['GET', 'POST'])
def upload_pic():
    # 获取传递过来的值,这里的值需要前后端配合。固定为upfile,这个属性可以修改,但是前端请求时也需要使用对应的属性
    file_target = request.files
    upfile = file_target['upfile'] if 'upfile' in file_target else None
    
    # 用于触发,set.js文件中的success方法,回显图片
    callback_target = 'window.parent'
    
    # 如果没有值,则弹窗显示上传失败。此处我们前后端未分离,后期可以修改为返回json格式的内容,由前端弹窗提示
    if upfile is None:
        return '<script>{0}.error("{1}")</script>'.format(callback_target, '上传失败')
    
    # 调用upload_file方法,实现图片上传,此方法在utils/utils.py文件中
    ret = upload_file(upfile)
    
    # 判断图片上传的返回值,给出不同反馈
    if ret['code'] != 200:
        return '<script>{0}.error("{1}")</script>'.format(callback_target, '上传失败:' + ret['msg'])
​
    return '<script>{0}.success("{1}")</script>'.format(callback_target, ret['data']['file_key'])
  • utils/utils.py中实现了upload_file方法,用于文件上传
python 复制代码
# 文件上传本地
def upload_file(file_storage):
    resp = {'code': 200, 'msg': '操作成功!', 'data': {}}
    # 获取文件名称
    filename = secure_filename(file_storage.filename)
    # 按照文件名进行分割,并且取后缀
    ext = filename.rsplit('.', 1)[1]
    # 如果该后缀名不在配置文件里面,那么就要返回错误消息
    if ext not in Config.UPLOAD['ext']:
        resp['code'] = -1
        resp['msg'] = '不允许的扩展类型文件'
        return resp
​
    file_dir = datetime.now().strftime('%Y%m%d')
    save_dir = Config.UPLOAD['prefix_path'] + file_dir
​
    if not os.path.exists(save_dir):
        os.makedirs(save_dir)
        os.chmod(save_dir, stat.S_IRWXU | stat.S_IRGRP | stat.S_IRWXO)
​
    # 构建文件名称
    file_name = str(uuid.uuid4().hex) + '.' + ext
    # 保存文件
    file_storage.save('{0}/{1}'.format(save_dir, file_name))
​
    # 将上传记录存储到数据库中
    add_file_obj = Files()
    add_file_obj.file_key = file_dir + '/' + file_name
    db.session.add(add_file_obj)
    db.session.commit()
​
    resp['data'] = {
        'file_key': add_file_obj.file_key
    }
​
    return resp
python 复制代码
# 上传图片
def upload_image():
    resp = {
        'state': 'SUCCESS',
        'url': '',
        'title': '',
        'original': ''
    }
    file_target = request.files
    upfile = file_target['upfile'] if 'upfile' in file_target else None
    if upfile is None:
        resp['state'] = '上传失败'
        return jsonify(resp)
​
    ret = upload_file(upfile)
    if ret['code'] != 200:
        resp['state'] = '上传失败:' + ret['msg']
    # 调用图片回显方法,传入图片名称
    resp['url'] = build_image_url(ret['data']['file_key'])

图片回显

python 复制代码
# 返回图片地址
def build_image_url(path):
    url = Config.DOMAIN + '/' + Config.UPLOAD['prefix_url'] + path
    return url

添加和编辑菜品

  • 富文本的添加图片逻辑类似。不过路由返回的是一个完整路径http://127.0.0.1:8999/static/upload/20250709/84a0dc4388154fd18c224cc6d3123270.jpg。方便后续在富文本中编译显示

  • 准备添加路由,开始添加和编辑菜品

python 复制代码
@manage_bp.route('/food/edit', methods=['GET', 'POST'])
def food_edit():
    resp = {'code': 200, 'msg': '操作成功', 'data': {}}
    if request.method == 'GET':
​
        resp_data = {}
        req = request.args
        f_id = int(req.get('id', 0))
​
        food_obj = None
        if f_id:
            food_obj = Food.query.get(f_id)
​
        cat_list = FoodCat.query.all()
        resp_data['info'] = food_obj
        resp_data['current'] = 'index'
        resp_data['cat_list'] = cat_list
​
        return ops_render('food/set.html', resp_data)
​
    if request.method == 'POST':
        req = request.values
​
        f_id = req['food_id'] if 'food_id' in req else 0
        c_id = int(req['cat_id']) if 'cat_id' in req else 0
        name = req['name'] if 'name' in req else ''
        price = req['price'] if 'price' in req else ''
        main_image = req['main_image'] if 'main_image' in req else ''
        summary = req['summary'] if 'summary' in req else ''
        stock = int(req['stock']) if 'stock' in req else ''
        tags = req['tags'] if 'tags' in req else ''
​
        price = Decimal(price).quantize(Decimal('0.00'))
​
        # if f_id < 1:
        #     resp['code'] = -1
        #     resp['msg'] = '商品不存在!'
        #     return jsonify(resp)
​
        if c_id < 1:
            resp['code'] = -1
            resp['msg'] = '请选择分类'
            return jsonify(resp)
​
        if len(name) < 1 or name is None:
            resp['code'] = -1
            resp['msg'] = '名称不符合规范'
            return jsonify(resp)
​
        if price <= 0 or price is None:
            resp['code'] = -1
            resp['msg'] = '售卖价格不能为空且大于等于0'
            return jsonify(resp)
​
        if main_image is None or len(main_image) < 3:
            resp['code'] = -1
            resp['msg'] = '请上传封面图'
            return jsonify(resp)
​
        if summary is None or len(summary) < 10:
            resp['code'] = -1
            resp['msg'] = '详情不能少于十个字符!'
            return jsonify(resp)
​
        if stock < 1:
            resp['code'] = -1
            resp['msg'] = '库存不能小于1'
            return jsonify(resp)
​
        if tags is None or len(tags) < 1:
            resp['code'] = -1
            resp['msg'] = '请输入标签!'
            return jsonify(resp)
​
        food_obj = Food.query.get(f_id)
        before_stock = 0
​
        if not food_obj:
            food_obj = Food()
        else:
            before_stock = food_obj.stock
​
        food_obj.cat_id = c_id
        food_obj.name = name
        food_obj.price = price
        food_obj.main_image = main_image
        food_obj.summary = summary
        food_obj.stock = stock
        food_obj.tags = tags
​
        db.session.add(food_obj)
        db.session.commit()
​
        stock_change = FoodStockChangeLog()
        stock_change.food_id = food_obj.id
        stock_change.unit = int(stock) - int(before_stock)
        stock_change.total_stock = stock
        stock_change.note = '后台调整'
        db.session.add(stock_change)
        db.session.commit()
​
        return jsonify(resp)
复制代码

显示所有菜品

python 复制代码
@manage_bp.route('/food/list')
def food_list():
    resp_data = {}
    # 有page就取page
    page = int(request.args.get('page', 1))
​
    query = Food.query
    # 有status就取status
    status_name = int(request.args.get('status', '-1'))
    if status_name > -1:
        query = query.filter(Food.status == status_name)
    # 有cat_id就取cat_id
    cat_id = int(request.args.get('cat_id', 0))
    if cat_id > 0:
        query = query.filter_by(cat_id=cat_id)
    # 有查询的信息就使用查询信息
    mix_kw = request.args.get('mix_kw', '')
    if mix_kw:
        rule = or_(Food.name.contains('%s' % mix_kw), Food.tags.contains('%s' % mix_kw))
        page_data = query.filter(rule).order_by(Food.id.desc()).paginate(page=page, per_page=Config.PER_PAGE)
    else:
        page_data = query.order_by(Food.id.desc()).paginate(page=page, per_page=Config.PER_PAGE)
​
    resp_data = {
        'list': page_data,
        'status_mapping': constants.STATUS_MAPPING
    }
    
    # 这里获取分类数据,用于筛选.
    food_list_obj = FoodCat.query.all()
    resp_data['current'] = 'index'
    resp_data['cat_list'] = food_list_obj
    return ops_render('food/index.html', resp_data)

查看菜品详情

  • 路由中接收传递过来的id值,根据id查询数据

  • 详情中,我们还需要展示当前菜品的库存变更记录

  • 后期还可以加上销售记录

python 复制代码
@manage_bp.route('/food/info')
def food_info():
    resp_data = {}
​
    req = request.args
    f_id = int(req.get('id', 0))
    if f_id < 1:
        return redirect('manage.food_list')
​
    food_obj = Food.query.get(f_id)
    if not food_obj:
        return redirect('manage.food_list')
    
    # 关联查询,库存记录变更表
    stock_change_list = FoodStockChangeLog.query.filter(FoodStockChangeLog.food_id == f_id).order_by(
        FoodStockChangeLog.id.desc()).all()
​
    resp_data['info'] = food_obj
    resp_data['current'] = 'index'
    resp_data['stock_change_list'] = stock_change_list
​
    return ops_render('food/info.html', resp_data)

删除菜品(修改状态)

  • 同理可得,根据传递过来的id和act的值,修改状态
python 复制代码
@manage_bp.route('/food/ops', methods=['PUT'])
def foot_ops():
    resp = {'code': 200, 'msg': '操作成功!', 'data': {}}
    req = request.values
​
    f_id = req['id'] if 'id' in req else 0
    act = req['act'] if 'act' in req else ''
    if not f_id:
        resp['code'] = -1
        resp['msg'] = '操作失败!'
        return jsonify(resp)
    if act not in ['remove', 'recover']:
        resp['code'] = -1
        resp['msg'] = '操作失败!'
        return jsonify(resp)
    food_obj = Food.query.get(f_id)
    if not food_obj:
        resp['code'] = -1
        resp['msg'] = '指定食物不存在!'
        return jsonify(resp)
    if act == 'remove':
        food_obj.status = 0
    elif act == 'recover':
        food_obj.status = 1
    db.session.commit()
    return jsonify(resp)
相关推荐
wr6 小时前
解决 NetMQ 创建Demo调试失败问题
后端
DashVector7 小时前
如何通过Java SDK获取Doc
大数据·后端·阿里巴巴
架构师沉默7 小时前
同事查日志太慢,我现场教他一套 grep 组合拳
java·后端·架构
知彼解己7 小时前
数据库事务隔离级别与 MVCC 机制详解
数据库
小李小李无与伦比7 小时前
MinerU环境部署——PDF转Markdown
开发语言·python·深度学习·conda
胡耀超7 小时前
AI:大语言模型微调的真相:打破迷思,理性选择
python·ai·大模型·llm·微调·提示词·大模型应用指南
前端fighter7 小时前
Express vs Koa vs Egg.js:Node.js 后端框架选型指南
前端·后端·面试
大学生毕业题目7 小时前
毕业项目推荐:52-基于yolov8/yolov5/yolo11的红绿灯检测识别系统(Python+卷积神经网络)
人工智能·python·yolo·目标检测·cnn·pyqt·红绿灯检测