当前位置: 首页 > news >正文

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

添加和编辑菜品模块

文件上传

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

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

 UPLOAD = {# 定义可上传的图片类型'ext': ['jpg', 'gif', 'bmp', 'jpeg', 'png'],# 普通文件保存路径'prefix_path': 'web/static/upload/',# 富文本图片路径'prefix_url': 'static/upload/'}
  • utils/views.py全局工具文件中

@utils_bp.route('/upload_pic', methods=['GET', 'POST'])
def upload_pic():# 获取传递过来的值,这里的值需要前后端配合。固定为upfile,这个属性可以修改,但是前端请求时也需要使用对应的属性file_target = request.filesupfile = 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方法,用于文件上传

# 文件上传本地
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'] = -1resp['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_namedb.session.add(add_file_obj)db.session.commit()
​resp['data'] = {'file_key': add_file_obj.file_key}
​return resp
# 上传图片
def upload_image():resp = {'state': 'SUCCESS','url': '','title': '','original': ''}file_target = request.filesupfile = file_target['upfile'] if 'upfile' in file_target else Noneif 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'])

图片回显

# 返回图片地址
def build_image_url(path):url = Config.DOMAIN + '/' + Config.UPLOAD['prefix_url'] + pathreturn url

添加和编辑菜品

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

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

@manage_bp.route('/food/edit', methods=['GET', 'POST'])
def food_edit():resp = {'code': 200, 'msg': '操作成功', 'data': {}}if request.method == 'GET':
​resp_data = {}req = request.argsf_id = int(req.get('id', 0))
​food_obj = Noneif f_id:food_obj = Food.query.get(f_id)
​cat_list = FoodCat.query.all()resp_data['info'] = food_objresp_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 0c_id = int(req['cat_id']) if 'cat_id' in req else 0name = 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'] = -1resp['msg'] = '请选择分类'return jsonify(resp)
​if len(name) < 1 or name is None:resp['code'] = -1resp['msg'] = '名称不符合规范'return jsonify(resp)
​if price <= 0 or price is None:resp['code'] = -1resp['msg'] = '售卖价格不能为空且大于等于0'return jsonify(resp)
​if main_image is None or len(main_image) < 3:resp['code'] = -1resp['msg'] = '请上传封面图'return jsonify(resp)
​if summary is None or len(summary) < 10:resp['code'] = -1resp['msg'] = '详情不能少于十个字符!'return jsonify(resp)
​if stock < 1:resp['code'] = -1resp['msg'] = '库存不能小于1'return jsonify(resp)
​if tags is None or len(tags) < 1:resp['code'] = -1resp['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_idfood_obj.name = namefood_obj.price = pricefood_obj.main_image = main_imagefood_obj.summary = summaryfood_obj.stock = stockfood_obj.tags = tags
​db.session.add(food_obj)db.session.commit()
​stock_change = FoodStockChangeLog()stock_change.food_id = food_obj.idstock_change.unit = int(stock) - int(before_stock)stock_change.total_stock = stockstock_change.note = '后台调整'db.session.add(stock_change)db.session.commit()
​return jsonify(resp)

显示所有菜品

@manage_bp.route('/food/list')
def food_list():resp_data = {}# 有page就取pagepage = int(request.args.get('page', 1))
​query = Food.query# 有status就取statusstatus_name = int(request.args.get('status', '-1'))if status_name > -1:query = query.filter(Food.status == status_name)# 有cat_id就取cat_idcat_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_objreturn ops_render('food/index.html', resp_data)

查看菜品详情

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

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

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

@manage_bp.route('/food/info')
def food_info():resp_data = {}
​req = request.argsf_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_objresp_data['current'] = 'index'resp_data['stock_change_list'] = stock_change_list
​return ops_render('food/info.html', resp_data)

删除菜品(修改状态)

  • 同理可得,根据传递过来的id和act的值,修改状态

@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 0act = req['act'] if 'act' in req else ''if not f_id:resp['code'] = -1resp['msg'] = '操作失败!'return jsonify(resp)if act not in ['remove', 'recover']:resp['code'] = -1resp['msg'] = '操作失败!'return jsonify(resp)food_obj = Food.query.get(f_id)if not food_obj:resp['code'] = -1resp['msg'] = '指定食物不存在!'return jsonify(resp)if act == 'remove':food_obj.status = 0elif act == 'recover':food_obj.status = 1db.session.commit()return jsonify(resp)

http://www.xdnf.cn/news/1422325.html

相关文章:

  • MIT 6.5840 (Spring, 2024) 通关指南——Lab 2: Key/Value Server
  • openssh 安装部署
  • 【Day 41】Shell脚本-循环
  • 802.11 和 802.1X
  • 谷歌-PCR-CA-联合训练并行小码本引入语义特征
  • wpf之WrapPanel
  • RAG-文本到SQL
  • 国别域名的SEO优势:是否更利于在当地搜索引擎排名?
  • Linux -- 进程间通信【System V共享内存】
  • 软考中级习题与解答——第二章_程序语言与语言处理程序(1)
  • vue社区网格化管理系统(代码+数据库+LW)
  • PRACH物理层详解
  • Flutter Container 阴影设置指南 2025版
  • 【技术选型】大型移动端跨平台应用开发 Flutter VS React Native
  • Web网络开发 -- Vue2基础语法,属性和生命周期
  • 大模型面试题剖析:全量微调与 LoRA 微调
  • TDengine 日期时间函数 DAYOFWEEK 使用手册
  • 特征增强方法【特征构建】
  • 太浅显数学常识暴露太重大数学真相:同样是有首项的无穷数列,此列的项可多于彼列的项
  • 车载卫星通信:让自动驾驶“永不掉线”?
  • STM32项目分享:基于单片机的图书馆座位监测系统
  • Git 版本管理工具基本操作汇总—命令总结
  • 液态神经网络(LNN)2:LTC改进成CFC详细推导过程
  • 使用 BayesFlow 神经网络简化贝叶斯推断的案例分享(二)
  • 液态神经网络:智能制造的新引擎
  • Android Framework打电话禁止播放运营商视频彩铃
  • FastLED库完全指南:打造炫酷LED灯光效果
  • 线程池发生了异常该怎么处理?
  • 多校区学校押金原路退回系统之免安装使用教程——东方仙盟
  • 本地部署开源临时文本分享服务 PrivateBin 并实现外部访问( Windows 版本)