def get_house_info(): logging = Use_Loggin() # 尝试从缓存中读取 try: req_data = redis_store.get("home_page_data") except Exception as e: logging.error("redis获取index缓存数据错误") req_data = None if req_data: logging.info("hit index page redis") # logging.info(req_data.decode("utf-8")) req_data = req_data.decode("utf-8") req = '{"errno":0, "errmsg":"OK", "data":%s}' % req_data, 200, { "Content-Type": "application/json" } print("req /house/index:", req) print("req type(req): ", type(req)) return req else: pass # redis没有数据, 数据库读取 try: # 返回房屋订单数目最多的5条数据 houses = House.query.order_by(House.order_count.desc()).limit( constants.HOME_PAGE_MAX_HOUSES) except Exception as e: logging.error("数据库--查询房屋订单数失败") return jsonify(errno=RET.DBERR, errmsg="查询失败") if not houses: return jsonify(errno=RET.NODATA, errmsg="没有数据") # 有多个房源信息, 用list作为容器, house_img_li = list() for house in houses: # logging.info(house.to_base_dict()) # {'house_id': 4, 'title': '123', # 'price': 12300, 'area_name': '海淀区', 'img_url': '', # 'room_count': 123, 'order_count': 0, 'address': '123', # 'user_avatar': 'http://qbg25zlw0.bkt.clouddn.com/FnNBWGcBkB9G3UamXjtfqnnD9lFM', # 'ctime': '2020-06-08'} house_img_li.append(house.to_base_dict()) # 将数据转成json(耗时), 并保存到redis json_houses = json.dumps(house_img_li) # '[{}, {}, {}]' try: redis_store.setex("home_page_data", value=json_houses, time=constants.HOME_PATH_REDIS_CACHE_EXPIRES) except Exception as e: logging.error("redis保存缓存失败") # return jsonify(errno=RET.OK, errmsg="OK", data={"data":json_houses}) 耗时 req2 = '{"errno"=0, "errmsg"="OK", "data":%s}' % json_houses, 200, { "Content-Type": "application/json" } return req2
def order_pay(order_id): logging = Use_Loggin() user_id = g.user_id # 判断订单状态: 存在, 在字符 try: orders = Order.query.filter(Order.id == order_id, Order.user_id == user_id, Order.status=="WAIT_PAYMENT").first() sun_amonut = str(orders.amount/100.0) # 总金额 except Exception as e: logging.error("订单数据查询失败") return jsonify(errno=RET.DBERR, errmsg="订单-数据库异常2") if orders is None: return jsonify(errno=RET.NODATA, errmsg="订单-订单数据有误") # 路径拼接 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) alipay_public_key_path = os.path.join(os.path.join(BASE_DIR, "keys_pay"), 'alipay_public_key.pem') app_private_key_path = os.path.join(os.path.join(BASE_DIR, "keys_pay"), 'app_private_key.pem') # 读取密钥数据 with open(alipay_public_key_path, "r", encoding="utf-8") as f: alipay_public_key_path_read = f.read() with open(app_private_key_path, "r", encoding="utf-8") as f: app_private_key_path_read = f.read() # 初始化阿里与支付模块 alipay_client = AliPay(appid=constants.ALIPAY_APIT_NUMS, # 沙箱环境的apid app_notify_url=None, # 回调, 不需要回调 app_private_key_string=app_private_key_path_read, # 给路径即可 alipay_public_key_string=alipay_public_key_path_read, sign_type="RSA2", # RSA或者 RSA2 debug=False) # 默认 # 手机网站支付 需要跳转到 https://openapi.alipaydev.com/gateway.do + order_string order_string = alipay_client.api_alipay_trade_wap_pay( subject=u"爱家租房 %s" % order_id, # 标题 out_trade_no=order_id, # 订单的编号 total_amount=sun_amonut, # 总金额 return_url="http://127.0.0.1:5000/ordersComplete.html", # 返回的链接地址 notify_url=None, ) # 构建用户跳转的支付宝链接地址 pay_url = constants.ALIPAY_URL_DEV_PRIFIX + order_string # 把链接发给前端 return jsonify(errno=RET.OK, errmsg="OK", data={"pay_url": pay_url})
def save_order_comment(order_id): logging = Use_Loggin() user_id = g.user_id # 获取参数 req_data = request.get_json() comment = req_data.get("comment") # 评价信息 # 检查参数 if not comment: return jsonify(errno=RET.PARAMERR, errmsg="参数错误") try: # 需要确保只能评论自己下的订单,而且订单处于待评价状态才可以 order = Order.query.filter(Order.id == order_id, Order.user_id == user_id, Order.status == "WAIT_COMMENT").first() house = order.house except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="无法获取订单数据") if not order: return jsonify(errno=RET.REQERR, errmsg="操作无效") try: # 将订单的状态设置为已完成 order.status = "COMPLETE" # 保存订单的评价信息 order.comment = comment # 将房屋的完成订单数增加1 house.order_count += 1 db.session.add(order) db.session.add(house) db.session.commit() except Exception as e: db.session.rollback() logging.error("数据库保存用户订单, 保存评价信息, 房屋订单数增加保存失败-220") return jsonify(errno=RET.DBERR, errmsg="操作失败") # 因为房屋详情中有订单的评价信息,为了让最新的评价信息展示在房屋详情中,所以删除Redis中关于本订单房屋的详情缓存 try: redis_store.delete("house_info_%s" % order.house.id) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.OK, errmsg="OK")
def get_user_house(): logging = Use_Loggin() user_id = g.user_id try: user = User.query.get(user_id) houses = user.houses except Exception as e: logging.error("数据库查询房东信息错误1") return jsonify(errno=RET.DBERR, errmsg="获取数据失败") # 将查询到的数据转成dict放到list中 houses_li = list() if houses: for house in houses: houses_li.append(house.to_base_dict()) # 数据库的基本信息 return jsonify(errno=RET.OK, errmsg="OK", data={"houses": houses_li})
def accept_reject_order(order_id): logging = Use_Loggin() user_id = g.user_id # 获取参数 req_data = request.get_json() if not req_data: return jsonify(errno=RET.PARAMERR, errmsg="参数错误") # action参数表明客户端请求的是接单还是拒单的行为 action = req_data.get("action") if action not in ("accept", "reject"): return jsonify(errno=RET.PARAMERR, errmsg="参数错误") try: # 根据订单号查询订单,并且要求订单处于等待接单状态 order = Order.query.filter(Order.id == order_id, Order.status == "WAIT_ACCEPT").first() house = order.house except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="无法获取订单数据") # 确保房东只能修改属于自己房子的订单 if not order or house.user_id != user_id: return jsonify(errno=RET.REQERR, errmsg="操作无效") if action == "accept": # 接单,将订单状态设置为等待评论 order.status = "WAIT_PAYMENT" elif action == "reject": # 拒单,要求用户传递拒单原因 reason = req_data.get("reason") if not reason: return jsonify(errno=RET.PARAMERR, errmsg="参数错误") order.status = "REJECTED" order.comment = reason try: db.session.add(order) db.session.commit() except Exception as e: db.session.rollback() logging.error("拒接接单-数据库保存错误180") return jsonify(errno=RET.DBERR, errmsg="操作失败") return jsonify(errno=RET.OK, errmsg="OK")
def save_order_payment_result(): """保存订单支付结果""" logging = Use_Loggin() alipay_dict = request.form.to_dict() # 对支付宝的数据进行分离 提取出支付宝的签名参数sign 和剩下的其他数据 alipay_signAture = alipay_dict.pop("sign") # 计算结果是很长的字符串 # 路径拼接 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) alipay_public_key_path = os.path.join(os.path.join(BASE_DIR, "keys_pay"), 'alipay_public_key.pem') app_private_key_path = os.path.join(os.path.join(BASE_DIR, "keys_pay"), 'app_private_key.pem') # 读取密钥数据 with open(alipay_public_key_path, "r", encoding="utf-8") as f: alipay_public_key_path_read = f.read() with open(app_private_key_path, "r", encoding="utf-8") as f: app_private_key_path_read = f.read() # 初始化 SDK工具对象 try: alipay_client = AliPay(appid=constants.ALIPAY_APIT_NUMS, app_notify_url=None, # 默认回调url app_private_key_string=app_private_key_path_read, # 私钥 alipay_public_key_string=alipay_public_key_path_read, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, sign_type="RSA2", # RSA 或者 RSA2 debug=False) # 默认False except Exception as e: logging.error("112行, 订单信息回调信息获取失败, 请管理员注意") return jsonify(errno=RET.THIRDERR, errmsg="订单信息回调失败") # 借助工具验证参数的合法性 # 如果确定参数是支付宝的,返回True,否则返回false try: result = alipay_client.verify(alipay_dict, alipay_signAture) except Exception as e: logging.error("支付回调失败") result = False return jsonify(errno=RET.THIRDERR, errmsg="支付错误") if result: # 修改数据库的订单状态信息 order_id = alipay_dict.get("out_trade_no") trade_no = alipay_dict.get("trade_no") # 支付宝的交易号 # order_id trade_no: 9 2020061822001403580501092285 try: # WAIT_COMMENT Order.query.filter_by(id=order_id).update({"status": "WAIT_COMMENT", "trade_no": trade_no}) db.session.commit() except Exception as e: logging.error("逻辑区提取数据失败") db.session.rollback() return jsonify(errno=RET.OK, errmsg="OK")
def set_user_name(): logging = Use_Loggin() # 获取参数 user_id = g.user_id # 能够登录装饰器, 说明一定有用户名, 就不验证了 reqs_data = request.get_json() if not reqs_data: return jsonify(errno=RET.NODATA, errmsg="参数不完整") row_user_name = reqs_data.get("name") if not row_user_name: return jsonify(errno=RET.NODATA, errmsg="名字未输入") # 用户名长度限制 if len(str(row_user_name)) > constants.USER_SET_NAME_LENG: return jsonify(errno=RET.PARAMERR, errmsg="用户名过长") # 校验参数, 用户名限制在字数以内, 不得使用特殊符号 for i in constants.USER_SET_NAME_NOT_INCLUDE: if i in row_user_name: booler = False break else: booler = True if booler is False: return jsonify(errno=RET.PARAMERR, errmsg="用户不得包含特殊字符") # 保存用户昵称name,并同时判断name是否重复(利用数据库的唯一索引) from ihome import db try: User.query.filter_by(id=user_id).update({"name": row_user_name}) # name = db.Column(db.String(32), unique=True, nullable=False) # 用户暱称 db.session.commit() except Exception as e: db.session.rollback() logging.error("用户保存用户名失败, 数据库更新失败") return jsonify(errno=RET.DBERR, errmsg="数据库设置用户名失败") session["name"] = row_user_name # 返回修改结果 return jsonify(errno=RET.OK, errmsg="修改成功", data={"name": row_user_name})
def ger_area_info(): logging = Use_Loggin() # 尝试从redis读取数据 try: resp_json = redis_store.get("area_info") except Exception as e: logging.error(e) else: if resp_json is not None: logging.info("hit redis: redis有地区数据") return resp_json, 200, {"Content-Type": "application/json"} else: pass # 获取城区信息, 不需要前端的参数, 查询数据库 try: areas_li = Area.query.all() except Exception as e: logging.error("数据库错误") return jsonify(errno=RET.DBERR, errmsg="城区-数据库查询错误") area_dict_li = list() for area in areas_li: area_dict_li.append(area.to_dict()) # 转换成json字符串, 将数据保存到redis中, 整体存取 res_dict = dict(errno=RET.OK, errmsg="OK", data=area_dict_li) resp_json = json.dumps(res_dict) # 保存到redis try: from ihome import constants redis_store.setex("area_info", value=resp_json, time=constants.EREA_INFO_CACHE_EXPIRES) except Exception as e: logging.warning("警告: json保存redis失败, 跳过") return resp_json, 200, {"Content-Type": "application/json"}
def login(): logging = Use_Loggin() # 参数提取 reqs_dice = request.get_json() mobile = reqs_dice.get("mobile") pwd = reqs_dice.get("password") # 参数校验 if not all([mobile, pwd]): return jsonify(error_num=RET.PARAMERR, errmsg="参数不完整") mobile_re = re.match(r'1[34578]\d{9}', mobile) if mobile_re == None: return jsonify(error_num=RET.PARAMERR, errmsg="手机号格式错误") # 判断错误次数, 保存到redis中, 时间限制 try: user_ip = request.remote_addr # "access_nums_ip地址": "次数" access_conut = redis_store.get("access_nums_%s" % user_ip) except Exception as e: logging.warning("警告: redis查询用户ip地址次数错误, 这里不限制访问, 让用户继续访问") else: if access_conut != None: if int(access_conut.decode( 'utf-8')) >= constants.LOGIN_MUNS_COUNTS: return jsonify(error_num=RET.REQERR, errmsg="请求次数过于频繁") else: pass # 比对数据库账号密码 try: user = User.query.filter_by(mobile=mobile).first() except: logging.error("错误: 数据库查询错误") return jsonify(error_num=RET.DATAERR, errmsg="获取用户信息失败") # 如果输入错误, 记录错误次数, 次数过多, 封ip if user is None or not user.check_pwd(pwd): # 如果找不到用户 or 密码 返回错误信息 try: # 额外配置, 错误后计数访问主机的ip地址 redis_store.incr("access_nums_%s" % user_ip, amount=1) redis_store.expire("access_nums_%s" % user_ip, time=constants.LOGIN_MUNS_NOTIME) except: pass # 因为用户名或者密码错误, 这里直接返回错误信息 return jsonify(error_num=RET.NODATA, errmsg="用户名或密码不存在") # 验证成功 from flask import session session["name"] = user.name session["mobile"] = user.mobile session["user_id"] = user.id return jsonify(errno=RET.OK, errms="登录成功")
def save_house_img(): logging = Use_Loggin() # 获取参数 # <input type="file" accept="image/*" name="house_image" id="house-image"> # <input type="hidden" name="house_id" id="house-id" value=""> raw_image_file = request.files.get("house_image") house_id = request.form.get("house_id") # 校验 if not all([raw_image_file, house_id]): return jsonify(errno=RET.PARAMERR, errmsg="参数不完整1") # 判断house_id正确性 try: house = House.query.get(house_id) except Exception as e: return jsonify(errno=RET.NODATA, errmsg="数据库查询房屋id失败, 请稍后再试") if house_id is None: return jsonify(errno=RET.NODATA, errmsg="房屋id不存在") image_data = raw_image_file.read() try: from ihome.utils.updown_image.seven_ox_coludy import down_load_of_Binary house_image_name = down_load_of_Binary(image_data) except Exception as e: logging.error("七牛云图片上传失败") return jsonify(errno=RET.THIRDERR, errmsg="上传失败3") # 保存数据 house_image = HouseImage(house_id=house_id, url=house_image_name) db.session.add(house_image) # 处理房屋的主图片 ''' 在第一次保存时, 设置了主图片为保存图片 如果是多次设置, 应该重写写接口设置为主图片 ? ''' if house.index_image_url is None or not house.index_image_url: house.index_image_url = house_image_name db.session.add(house) try: db.session.commit() except Exception as e: db.session.rollback() logging.error("数据库保存房屋图片信息异常") return jsonify(errno=RET.DATAERR, errmsg="数据库保存失败") image_url = constants.URL_OF_QINIU_IMAGE_PREFIX + house_image_name return jsonify(errno=RET.OK, errmsg="OK", data={"image_url": image_url})
def sendTemplateSMS(self, to, datas, tempId): try: result = self.rest.sendTemplateSMS(to, datas, tempId) except Exception as e: try: from ihome.utils.use_logging import Use_Loggin logg = Use_Loggin() logg.error(e) logg.error("短信发送错误, 请查看Send_Temp模块是否有误") except: print("logg模块导入错误, 请查看是否有误") raise e success = "<statusCode>000000</statusCode>" if success in result: return True else: return False
def get_user_orders(): logging = Use_Loggin() user_id = g.user_id print("查询用户订单信息 user_id: ", user_id) # 用户的身份,用户想要查询作为房客预订别人房子的订单,还是想要作为房东查询别人预订自己房子的订单 # /api/v1.0/user/orders?role=custom role = request.args.get(key="role", default="") print("role: ", role) # 查询订单数据 try: if "landlord" == role: # 房东查询订单 houses = House.query.filter(House.user_id == user_id).all() houses_ids = [house.id for house in houses] # 再查询预订了自己房子的订单 orders = Order.query.filter( Order.house_id.in_(houses_ids)).order_by( Order.create_time.desc()).all() else: # 游客身份查询订单 orders = Order.query.filter(Order.user_id == user_id).order_by( Order.create_time.desc()).all() except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="查询订单信息失败") # 将订单对象转换为字典数据 orders_dict_list = [] if orders: for order in orders: orders_dict_list.append(order.to_dict()) print("查询成功, 返回信息orders_dict_list: ", orders_dict_list) return jsonify(errno=RET.OK, errmsg="OK", data={"orders": orders_dict_list})
def set_use_avatar(): logging = Use_Loggin() # 获取用户参数: 用户id() 图片(多媒体表单, 二进制) user_id = g.user_id # 装饰器代码中已经将user_id保存在g对象, 所以视图可以直接读取 # 获取图片 row_image_file = request.files.get("avatar") if row_image_file is None: return jsonify(errno=RET.PARAMERR, errmsg="未上传图片") image_data = row_image_file.read() # 调用七牛云平台上传图片 try: # 正常应该返回文件名 image_file_name = down_load_of_Binary(image_data) except Exception as e: logging.error(e) return jsonify(errno=RET.THIRDERR, errmsg="上传服务器失败2") # http://www.mylady.top/static/note_flask --第21节 ''' In [31]: User.query.all() Out[31]: [User object: name=ying, User object: name=chen, User object: name=zhou] In [32]: User.query.filter_by(name='chen').update({'name':'cheng'}) Out[32]: 1 In [33]: User.query.all() Out[33]: [User object: name=ying, User object: name=cheng, User object: name=zhou] ''' from ihome import db try: User.query.filter_by(id=user_id).update({"avatar_url": image_file_name}) db.session.commit() except Exception as e: db.session.rollback() # 回滚 logging.error(e) return jsonify(errno=RET.DATAERR, errmsg="数据库保存用户图片url地址失败") # 成功 from ihome.constants import URL_OF_QINIU_IMAGE_PREFIX http_image_url = str(URL_OF_QINIU_IMAGE_PREFIX + image_file_name) # 拼接为完整图片url地址 return jsonify(errno=RET.OK, errmsg="图上保存成功", data={"image_file_name": http_image_url})
def get_msm_code(msg_code_phone): logg = Use_Loggin() # 获取日志对象 # 获取参数 phone_nums = msg_code_phone # 获取: 手机号这个参数 image_code = request.args.get("image_code") # 获取: 验证码真实值 image_code_id = request.args.get("image_code_id") # 获取: 验证码对应的图片, 需要及时删除 Js生成的UUID # 校验数据 if not all([image_code, image_code_id]): return jsonify(error_num=RET.DATAERR, errmsg="参数不完整") # 从redis取出 真实的图片value from ihome.utils.response_code import RET try: real_image_code = redis_store.get("image_code_%s" % image_code_id) except Exception as e: logg.error("错误, 短信验证--redis_store.get(image_code_ image_code_id)提取信息错误") return jsonify(error_num=RET.DBERR, errmsg="Redis 数据库异常") if real_image_code is None: return jsonify(error_num=RET.NODATA, errmsg="Redis 没有验证码信息") # -------------判断验证码值是否正确------------- # print("real_image_code: ", real_image_code, " real_image_code.lower(): ", real_image_code.lower().decode('utf-8')) # print("image_code: ", image_code, " image_code.lower(): ", image_code.lower()) # print(type(real_image_code.lower())) # -存在撞库风险, 如果在之后删除redis数据, # 为什么选择这里 ? try: redis_store.delete("image_code_%s" % image_code_id) except Exception as e: logg.warning("警告: Redis删除验证码图片失败 (非主要错误) , ") logg.warning(e) if real_image_code.lower().decode('utf-8') != image_code.lower(): return jsonify(error_num=RET.DBERR, errmsg="图片验证码错误") # 判断对于手机号操作, 60s之内不允许操作 try: second_info = redis_store.get("def_sms_code_%s" % phone_nums) except Exception as e: pass else: if second_info is not None: return jsonify(error_num=RET.REQERR, errmsg="请求频繁") # 手机号是否存在 try: user = User.query.filter_by(mobile=phone_nums).first() except Exception as e: user = None logg.error("注册时, 数据库手机号查询错误") else: if user is not None: return jsonify(error_num=RET.DATAEXIST, errmsg="注册手机已存在") # 返回短信验证码, 保存在 redis中 from random import randint sms_code = "%06d" % randint(0, 999999) # 发送的验证码真实值 try: # 有效期 from ihome.constants import MSG_CODE_REDIS_EXPIES # 保存到 redis的验证码值 redis_store.setex("sms_code_%s" % phone_nums, value=sms_code, time=MSG_CODE_REDIS_EXPIES) # 保存60s设置, 防止60s内再次触发发送短信的请求 redis_store.setex("def_sms_code_%s" % phone_nums, value="1", time=MSG_CODE_LONG_EXPIES) except Exception as e: logg.error("注册时, 保存短信验证码异常1") logg.error(e) return jsonify(error_num=RET.DBERR, errmsg="Redis 保存短信验证码异常") # 异步发送短信 windows不支持 celery ? # try: # from ihome.task.sms_send_tasks import send_sms # send_sms.delay(phone_nums, # [sms_code, # int(MSG_CODE_REDIS_EXPIES / 60)], # 1) # return jsonify(error_num=RET.OK, errmsg="短信发送成功") # except Exception as e: # logg.error("异步发送邮件失败, 使用同步发送邮件") # 同步发送邮件 try: from ihome.constants import MSG_CODE_REDIS_EXPIES # 提取配置文件的设置 from ihome.libs.Send_SMS.Demo_Send import CCP ccp = CCP.instance() res = ccp.sendTemplateSMS(phone_nums, [sms_code, int(MSG_CODE_REDIS_EXPIES/60)], 1) # 5是有效期, 1是模板 except Exception as e: logg.error("注册时, 保存短信验证码异常2") logg.error(e) return jsonify(error_num=RET.DBERR, errmsg="保存短信验证码异常") if res: # 发送成功 return jsonify(error_num=RET.OK, errmsg="短信发送成功") else: return jsonify(error_num=RET.THIRDERR, errmsg="短信发送失败")
def save_order(): logging = Use_Loggin() user_id = g.user_id # 获取参数 order_data = request.get_json() if not order_data: return jsonify(errno=RET.PARAMERR, errmsg="参数错误") house_id = order_data.get("house_id") # 预订的房屋编号 start_date_str = order_data.get("start_date") # 预订的起始时间 end_date_str = order_data.get("end_date") # 预订的结束时间 print("house_id, start_date_str, end_date_str: ", house_id, start_date_str, end_date_str) # 检查参数是否都有 if not all((house_id, start_date_str, end_date_str)): return jsonify(errno=RET.PARAMERR, errmsg="参数错误") # 日期格式检查 try: # 将请求的时间参数字符串转换为datetime类型 start_date = datetime.strptime(start_date_str, "%Y-%m-%d") end_date = datetime.strptime(end_date_str, "%Y-%m-%d") assert start_date <= end_date # 计算预订的天数 days = (end_date - start_date).days + 1 # datetime.timedelta except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.PARAMERR, errmsg="日期格式错误") # 查询房屋是否存在 try: house = House.query.get(house_id) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="获取房屋信息失败") if not house: return jsonify(errno=RET.NODATA, errmsg="房屋不存在") # 预订的房屋是否是房东自己的 if user_id == house.user_id: return jsonify(errno=RET.ROLEERR, errmsg="不能预订自己的房屋") print("user_id: ", user_id) # 确保用户预订的时间内,房屋没有被别人下单 try: # 查询时间冲突的订单数 count = Order.query.filter(Order.house_id == house_id, Order.begin_date <= end_date, Order.end_date >= start_date).count() # select count(*) from order where .... except Exception as e: logging.error("数据库查询Order订单失败5") return jsonify(errno=RET.DBERR, errmsg="检查出错,请稍候重试") if count > 0: return jsonify(errno=RET.DATAERR, errmsg="房屋已被预订") # 订单总额 amount = days * house.price print("amount: ", amount) # 保存订单数据 order = Order(house_id=house_id, user_id=user_id, begin_date=start_date, end_date=end_date, days=days, house_price=house.price, amount=amount) try: db.session.add(order) db.session.commit() except Exception as e: logging.error("订单数据-数据库保存失败3") current_app.logger.error(e) db.session.rollback() return jsonify(errno=RET.DBERR, errmsg="保存订单失败") print("订单保存ok") return jsonify(errno=RET.OK, errmsg="OK", data={"order_id": order.id})
def get_house_detail(house_id): """ 前端在房屋详情页面展示时,如果浏览页面的用户不是该房屋的房东,则展示预定按钮,否则不展示 """ logging = Use_Loggin() # 尝试获取用户登录的信息,若登录,则返回给前端登录用户的user_id,否则返回user_id=-1 user_id = session.get("user_id", "-1") if not house_id: return jsonify(errno=RET.PARAMERR, errmsg="参数缺失") # 从redis提取数据 try: ret = redis_store.get("house_info_%s" % house_id) except Exception as e: ret = None logging.warning(e) if ret: logging.info("hit house info redis") ret = ret.decode("utf-8") resp = '{"errno":0, errmsg:"OK", "data":{"user_id":%s, "house":%s}}' % ( user_id, ret), 200, { "Content-Type": "application/json" } return resp # 如果redis没有数据, 查询数据库--用户未登录也会使用sql查询 try: house = House.query.get(house_id) # 查询是不是房东在访问 logging.info("缓存无数据, 从sql中提取") except Exception as e: logging.error("数据库查询用户登录信息错误") return jsonify(errno=RET.DBERR, errmsg="查询错误") if not house: return jsonify(errno=RET.NODATA, errmsg="数据不存在") try: house_data = house.full_info_dict() except Exception as e: logging.error("数据库查询失败2") return jsonify(errno=RET.DATAERR, errmsg="查询错误2") json_house = json.dumps(house_data) try: redis_store.setex("house_info_%s" % user_id, value=json_house, time=constants.HOUSE_DETAIL_REDIS_CACHE_EXPIRES) except Exception as e: logging.error("Reids保存缓存错误") test_li = list() for i in range(25): a = {"%s" % i: "%s" % i} test_li.append(a) test_json = json.dumps(test_li) resp2 = '{"errno":"0", "errmsg":"OK", "data":{"user_id":%s, "house":%s, "test_json":%s}}' % ( user_id, json_house, test_json), 200, { "Content-Type": "application/json" } return resp2 # 返回信息
def register(): logging = Use_Loggin() """ 请求参数: 1. 手机号 2. 短信验证码 3. 密码, 确认密码 参数格式: json :return: """ from flask import request req_dict = request.get_json() # 获取请求的json, 返回字典 mobile = req_dict.get("mobile") sms_code = req_dict.get("sms_code") password = req_dict.get("password") password2 = req_dict.get("password2") # 校验参数 if not all([mobile, sms_code, password, password2]): return jsonify(error_num=RET.PARAMERR, errmsg="数据不完整") # 校验手机格式 if not re.match(r"1[34578]\d{9}", mobile): return jsonify(error_num=RET.PARAMERR, errmsg="手机格式不正确") # 校验密码 if password != password2: return jsonify(error_num=RET.PARAMERR, errmsg="两次输入密码不一致") # 业务逻辑处理, 从 redis取出短信验证码 try: # 注意: 从redis提取的数据属于 bytes类型, 需要decode real_sms_txt = redis_store.get("sms_code_%s" % mobile) except Exception as e: logging.error("redis数据读取错误") logging.error(e) return jsonify(error_num=RET.PARAMERR, errmsg="读取真实短信验证码异常") # 判断短信验证码是否过期 if real_sms_txt is None: return jsonify(error_num=RET.NODATA, errmsg="短信验证码过期") if constants.MSG_CODE_True_OR_False is False: # 删除redis中的短信验证码, 防止校验失败后的重复校验 这里我不删除, 短信可以重复利用 try: redis_store.delete("sms_code_%s" % mobile) except Exception as e: logging.error("短信验证码删除失败") logging.error(e) # 判断用户填写的短信验证码的正确性 # print("->"*10, type(real_sms_txt), real_sms_txt, type(sms_code), sms_code) # <class 'bytes'> b'075857' <class 'str'> 075857 if real_sms_txt.decode("utf-8") != sms_code: return jsonify(error_num=RET.DATAERR, errmsg="短信验证码错误") # 判断手机号是否注册过 # 手机号是否存在 from ihome.models import User try: user = User.query.filter_by(mobile=mobile).first() except Exception as e: logging.error("注册时, 数据库手机号查询错误") logging.error(e) return jsonify(error_num=RET.DATAERR, errmsg="数据库查询是否重复手机号时异常") else: if user != None: return jsonify(error_num=RET.DATAEXIST, errmsg="注册手机已存在") # 保存到数据库中 # 加密处理 user = User(name=mobile, mobile=mobile) # user.generate_password_hash(password) user.password = password # 设置值 # print(user.password()) # 读取值--设置了报错 try: db.session.add(user) db.session.commit() # 数据正式保存 except IntegrityError as e: db.session.rollback() # 数据库操作错误的回滚 logging.error(e) logging.error("手机号出现重复值, 用户已经注册") return jsonify(error_num=RET.DATAEXIST, errmsg="手机号出现重复值") except Exception as e: logging.error(e) logging.error("数据库出现了问题") return jsonify(error_num=RET.DATAEXIST, errmsg="查询数据库异常") # 保存登录状态到session中 from flask import session # 从flask中导入全局的请求上下文 session["name"] = mobile session["mobile"] = mobile session["user_id"] = user.id return jsonify(errno=RET.OK, errmsg="用户注册成功")
def search_house(): logging = Use_Loggin() # 获取参数, 可有可无 # http://127.0.0.1:5000/search.html?aid=1&aname=%E4%B8%9C%E5%9F%8E%E5%8C%BA&sd=2020-06-23&ed=2020-07-25 start_date = request.args.get(key="sd", default="") # 用户想要的起始时间 sd=2020-06-23 end_date = request.args.get(key="ed", default="") # 结束时间 ed=2020-07-25 area_id = request.args.get(key="aid", default="") # 区域编号 aname=东城区 sort_key = request.args.get(key="ks", default="new") # 排序关键字 page = request.args.get(key="p", default="") # 页数 # print("1 start_date: ", start_date, type(start_date)) for test # print("1 end_date: ", end_date, type(end_date)) for test # print("1 area_id: ", area_id, type(area_id)) for test # print("1 sort_key: ", sort_key, type(sort_key)) for test # print("1 page: ",page , type(page)) for test # 因为参数可传可不传, 所以这里参数校验没必要 # try: # if start_date is not None: # start_date = datetime.strftime(start_date, "%Y-%m-%d") # print("start_date 2: ", start_date) # if end_date is not None: # end_date = datetime.strftime(end_date, "%Y-%m-%d") # print("end_date 2: ", end_date) # # if start_date and end_date is not None: # assert end_date <= start_date # # except Exception as e: # return jsonify(errno=RET.PARAMERR, errmsg="日期输入有误") # 区域判断 try: areas = Area.query.get(area_id) except Exception as e: return jsonify(errno=RET.PARAMERR, errmsg="区域信息有误") # 处理页数 try: page = int(page) except Exception as e: page = 1 # 查询数据库 # 获取缓存数据 存储每个搜索组合, 增加内存开销 redis_key = "house_%s_%s_%s_%s" % (start_date, end_date, area_id, sort_key) try: resp_json = redis_store.hget(redis_key, page) except Exception as e: resp_json = None logging.error("reids 获取缓存失败") else: if resp_json: return resp_json, 200, {"Content-Type": "application/json"} # 过滤条件的参数列表容器 filter_params = list() # 形成参数: 填充过滤参数 时间条件 conflict_orders = None try: if start_date and end_date: # 查询冲突的订单 conflict_orders = Order.query.filter( Order.begin_date <= end_date, Order.end_date >= start_date).all() elif start_date: conflict_orders = Order.query.filter( Order.end_date >= start_date).all() elif end_date: conflict_orders = Order.query.filter( Order.begin_date <= end_date).all() except Exception as e: logging.error("Order数据库查询错误") return jsonify(errno=RET.DBERR, errmsg="数据库异常") if conflict_orders: # 从订单中获取冲突的房屋id conflict_house_ids = [order.house_id for order in conflict_orders] # 如果冲突的房屋id不为空,向查询参数中添加条件 if conflict_house_ids: filter_params.append(House.id.notin_(conflict_house_ids)) # 区域条件 if area_id: # 放进去的是表达式: __eq__()方法的执行 filter_params.append(House.area_id == area_id) # 查询数据库 # 补充排序条件 if sort_key == "booking": # 入住做多 house_query = House.query.filter(*filter_params).order_by( House.order_count.desc()) elif sort_key == "price-inc": house_query = House.query.filter(*filter_params).order_by( House.price.asc()) elif sort_key == "price-des": house_query = House.query.filter(*filter_params).order_by( House.price.desc()) else: # 新旧 house_query = House.query.filter(*filter_params).order_by( House.create_time.desc()) # 处理分页 try: # 当前页数 每页数据量 自动的错误输出 page_obj = house_query.paginate( page=page, per_page=constants.HOUSE_LIST_PAGE_CAPACITY, error_out=False) except Exception as e: logging.error("数据库查询错误") return jsonify(errno=RET.DBERR, errmsg="数据库异常") # 获取页面数据 house_li = page_obj.items houses = [] for house in house_li: houses.append(house.to_base_dict()) # 获取总页数 total_page = page_obj.pages resp_dict = dict(errno=RET.OK, errmsg="OK", data={ "total_page": total_page, "houses": houses, "current_page": page }) resp_json = json.dumps(resp_dict) if page <= total_page: # 设置缓存数据 redis_key = "house_%s_%s_%s_%s" % (start_date, end_date, area_id, sort_key) # 哈希类型 try: # redis_store.hset(redis_key, page, resp_json) # redis_store.expire(redis_key, constants.HOUES_LIST_PAGE_REDIS_CACHE_EXPIRES) # 创建redis管道对象,可以一次执行多个语句 pipeline = redis_store.pipeline() # 开启多个语句的记录 pipeline.multi() pipeline.hset(redis_key, page, resp_json) pipeline.expire(redis_key, constants.HOUES_LIST_PAGE_REDIS_CACHE_EXPIRES) # 执行语句 pipeline.execute() except Exception as e: logging.error("redis设置错误") return resp_json, 200, {"Content-Type": "application/json"}
def send_houses_info(): ''' 前端发送过来的json数据 { "title":"", "price":"", "area_id":"1", "address":"", "room_count":"", "acreage":"", "unit":"", "capacity":"", "beds":"", "deposit":"", "min_days":"", "max_days":"", "facility":["7","8"] } ''' logging = Use_Loggin() # 获取参数 user_id = g.user_id house_dict = request.get_json() title = house_dict.get("title") price = house_dict.get("price") area_id = house_dict.get("area_id") address = house_dict.get("address") room_count = house_dict.get("room_count") acreage = house_dict.get("acreage") unit = house_dict.get("unit") # 房屋布局 capacity = house_dict.get("capacity") # 房屋容纳数量 beds = house_dict.get("beds") deposit = house_dict.get("deposit") # 押金 min_days = house_dict.get("min_days") max_days = house_dict.get("max_days") facility_ids = house_dict.get("facility") # 设施可能是空 # 校验参数, facility另外校验 if not all([ title, price, area_id, address, room_count, acreage, unit, capacity, beds, deposit, min_days, max_days ]): return jsonify(errno=RET.PARAMERR, errmsg="参数不完整") # 金额校验 try: price = int(float(price) * 100) deposit = int(float(deposit) * 100) except Exception as e: return jsonify(errno=RET.PARAMERR, errmsg="参数错误") # 校验城区id是否存在 try: area_sql_id = Area.query.get(area_id) except Exception as e: area_sql_id = None if area_sql_id is None: return jsonify(errno=RET.PARAMERR, errmsg="城区信息有误") # 其他--校验--略 # 保存数据 house = House(user_id=user_id, area_id=area_id, title=title, price=price, address=address, room_count=room_count, acreage=acreage, unit=unit, capacity=capacity, beds=beds, deposit=deposit, min_days=min_days, max_days=max_days) # 仅仅保存到session, 不报错 db.session.add(house) # 处理房屋的设施信息, if facility_ids is not None: # ['7', '8'] try: facility_obj = Facility.query.filter( Facility.id.in_(facility_ids)).all() except Exception as e: logging.error("设备信息数据库查询异常") return jsonify(errno=RET.DBERR, errmsg="数据库查询异常") if facility_obj: # 有合法的设施数据 house.facilities = facility_obj try: db.session.add(house) db.session.commit() except Exception as e: db.session.rollback() logging.error("数据库保存失败") return jsonify(errno=RET.DBERR, errmsg="房屋信息统一提交数据失败") return jsonify(errno=RET.OK, errmsg="保存数据成功", data={"house_id": house.id})