def get_house_detail(house_id): """get house detail""" # 前端在房屋详情页面展示时,如果浏览页面的用户不是该房屋的房东,则显示预定按钮,否则不显示, # 所以需要在后端返回登录用户的user_id # 尝试获取用户的登录的信息,若登录,则返回给前端登录用户的user_id,否则返回user_id = -1 login_user_id = session.get("user_id", "-1") # verify args if not house_id: return jsonify(errno=RET.PARAMERR, errmsg="args error") # get data from redis first try: ret = redis_store.get("house_info_%s" % house_id) except Exception as e: current_app.logger.error(e) ret = None if ret: current_app.logger.info("hit house info redis") return '{"errno":"0", "errmsg":"OK", "data":{"login_user_id":%s, "house":%s}}' % (login_user_id, ret), \ 200, {"Content-Type": "application/json"} # query DB try: house = House.query.get(house_id) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="query DB failed") if not house: return jsonify(errno=RET.NODATA, errmsg="house not exist") # convert house obj to dict try: house_data = house.to_full_dict() except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DATAERR, errmsg="data error 1") # save data to redis json_house = json.dumps(house_data) try: redis_store.setex("house_info_%s" % house_id, constants.HOUSE_DETAIL_REDIS_EXPIRE_SECOND, json_house) except Exception as e: current_app.logger.error(e) resp = '{"errno":"0", "errmsg":"OK", "data":{"login_user_id":%s, "house":%s}}' % (login_user_id, json_house), \ 200, {"Content-Type": "application/json"} return resp
def get_house_index(): """get the house info displayed on the slides on the home page""" # try to get the cache data from redis try: ret = redis_store.get("home_page_data") except Exception as e: current_app.logger.error(e) # recover the return data to None # 如果出现异常,继续往下走回抛出异常:ret还没有被定义过, so define "ret = None" ret = None if ret: current_app.logger.info("hit house index info redis") # cause the storage_Type in redis is json_string, so return 执行字符串拼接 directly, return '{"errno":0, "errmsg":"OK", "data":%s}' % ret, 200, {"Content-Type": "application/json"} else: try: # do not need to show all the house data # query DB, and return the data of house'order count more then 5 record houses = House.query.order_by(House.order_count.desc()).limit(constants.HOME_PAGE_MAX_HOUSES) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg="query DB failed") if not houses: return jsonify(errno=RET.NODATA, errmsg="query return NODATA") houses_list = [] for house in houses: # if house has not set default image, jump if not house.index_image_url: continue houses_list.append(house.to_basic_dict()) # convert the data to json_str, and save to redis cache json_houses = json.dumps(houses_list) try: redis_store.setex("home_page_data", constants.HOME_PAGE_DATA_REDIS_EXPIRES, json_houses) except Exception as e: current_app.logger.error(e) # return json_str 字符串拼接 , because it's more quickly then jsonify() function return '{"errno":0, "errmsg":"OK", "data":%s}' % json_houses, 200, {"Content-Type": "application/json"}
def get_area_info(): """获取区域信息""" # try to get data from redis try: resp_json = redis_store.get("area_info") except Exception as e: current_app.logger.error(e) else: if resp_json is not None: # cache data in redis current_app.logger.info("hit redis area_info") return resp_json, 200, {"Content-Type": "application/json"} # 查新数据库 try: # 查询出所有的数据到列表 area_li = Area.query.all() except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg='数据库异常') area_dict_li = [] # 将每一个城区信息对象转换为字典,然后拼接到列表中 for area in area_li: area_dict_li.append(area.to_dict()) # 将数据转换为json字符串,使用函数dict()将字典类型的数据转换成为json type string # save to redis resp_dict = dict(errno=RET.OK, errmsg='OK', data=area_dict_li) resp_json = json.dumps(resp_dict) # 将数据保存到redis中,整体存,整体取 try: # (name, expires_time, key) # must set area_data expire_time for the issue of sync_problem between redis and mysql redis_store.setex("area_info", constants.AREA_INFO_REDIS_EXPIRES, resp_json) except Exception as e: current_app.logger.error(e) # 将查询到的数据data和对应的信息返回 return resp_json, 200, {"Content-Type": "application/json"}
def get_image_code(image_code_id): """ 获取验证码图片 :param image_code_id: 图片验证码编号(需要接收) :return: 如果出现异常,返回异常信息,否则,返回验证码图片 """ # 套路:获取参数,检验参数,业务逻辑处理,返回值 # 生成验证码图片 # 名字,真实文本,图片数据 name, text, image_code = captcha.generate_captcha() # 将编号以及验证码的真实值保存到redis(选择字符串)中,并设置有效期(自定义有效期为180秒,设置成了常量,在constants中) # redis: # 字符串:"key":xxx <-- # 列表:(redis中的列表保存的还是字符串的值,和python有本质的区别)image_codes:["编号:","",""] -----麻烦 # 哈希:"image_codes":{"id1":"abc","":""} 里面存放的还是字符串, 哈希使用的方法 hset("image_code","id1","abc"), 有就取,没有就存 --有效期不方便 # 选用单条维护记录,选用字符串,直接使用set函数设置字符串即可 # redis_store.set('iamge_code_%s' % image_code_id, text) # redis_store.expire('image_code_%s' % image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES) # 将以上合并写,setex(记录名,有效期,记录值), 网络连接可能有问题,使用要捕获一下异常,默认保存在0号数据库 # Redis Setex命令为指定的key设置值及其过期时间。如果key已经存在, SETEX命令将会替换旧的值。SETEX KEY_NAME TIMEOUT VALUE try: redis_store.setex('image_code_%s' % image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text) except Exception as e: # 记录日志 current_app.logger.error(e) # return jsonify(errno=RET.DBERR, errmsg="save image code failed") # 出现异常,没有必要返回图片了,返回json格式的提示使用jsonify()函数 return jsonify(errno=RET.DBERR, errmsg="保存图片验证码失败") # 没有异常 返回验证码图片,并指定一下头make_response:修改内容类型Content-Type(默认为test/html)类型为image,不改不认识图片 resp = make_response(image_code) resp.headers['Content-Type'] = 'image/jpg' return resp
def get_sms_code(phone_num): """ 获取短信验证码 1.获取参数 2.校验参数 3.业务处理 4.从redis中取出真实的图片验证码 5.与用户填写的信息进行对比 6.判断手机号是否存在 7.如果手机号不存在,则生成短信验证码 8.保存真实的短信验证码 9.发送短信 10.返回值 :param mobile: :return: """ # 获取参数, args是一个字典 image_code = request.args.get('image_code') image_code_id = request.args.get('image_code_id') # 检验参数all()校验参数是否完整 if not all([image_code, image_code_id]): # 表示参数不完整,返回json return jsonify(errno=RET.PARAMERR, errmsg='参数不完整') # 逻辑处理 # 从redis中取出验证码图片的真实值, 进行网络操作可能会出现错误,需要捕获一下 try: real_image_code = redis_store.get('image_code_%s' % image_code_id) except Exception as e: current_app.logger.error(e) # return jsonify(errno=RET.DBERR, errmsg='数据库异常') # 可能过期,判断真实值是否过期,redis中如果过期则返回None if real_image_code is None: return jsonify(errno=RET.NODATA, errmsg='验证码失效') # 删除redis中的图片验证码,防止用户使用同一个验证码验证多次 try: redis_store.delete("image_code_%s" % image_code_id) except Exception as e: # 这里删除验证码不成功也不会造成崩溃,不用直接返回给用用户,返回是没有道理的,让用户验证就可以 current_app.logger.error(e) # 验证用户填写的验证码与redis中的真实值是否相等,统一为小写,python3中会出现b''这种情况,需要在初始化链接redis的时候设置参数decode_responses=True # print(image_code) # 3Mj9 # print(real_image_code) # b'3Mj9' if image_code.lower() != real_image_code.lower(): return jsonify(errno=RET.DATAERR, errmsg='图片验证码错误') # 判断对于这个手机号的操作,在60秒内有没有之前的记录,如果有,则认为用户操作频繁,不接受处理 try: send_flag = redis_store.get("send_sms_code_%s" % phone_num) except Exception as e: current_app.logger.error(e) else: if send_flag is not None: # 表示在60秒之前有过发送的记录 return jsonify(errno=RET.REQERR, errmsg="请求过于频繁,请于60秒之后重试") # 判断手机号是否已注册 # 对数据库的操作需要把异常捕获补上:这里的异常捕获和else逻辑集合使用 try: # 有且只有一条,否则是没有,所以使用first()函数过滤 user = User.query.filter_by(phone_num=phone_num).first() except Exception as e: # 如果数据库出现问题只把错误信息保存下来(因为不想失去用户),否则会走下面的else逻辑 current_app.logger.error(e) else: # user对象能够存在的前提是没有发生异常,如果发生异常user可能就没有,所以这里应该使用else进行判断 # 在Django中获取单条记录不存在时会抛出异常,凡是在Flask中会返回None值 if user is not None: # 表示手机号已经存在 return jsonify(errno=RET.DATAEXIST, errmsg='手机号已注册') # 生成短信验证码 6 位, "%06d"的意思就是保证有6位数,不够前面补0 # import random sms_code = "%06d" % random.randint( 0, 999999) # %06d 表示生成6位整数,不够的前边补0 ,如029541 # 保存短信验证码到redis中 try: # 由于有效期,所以单条存储数据,使用字符串类型 redis_store.setex("sms_code_%s" % phone_num, constants.SMS_CODE_REDIS_EXPIRES, sms_code) # 保存发送给这个手机号的记录,防止用户在60s内再次发出短信验证码操作, 1这个键说明的是存在(仅仅作为一个记录) redis_store.setex("send_sms_code_%s" % phone_num, constants.SEND_SMS_CODE_INTERVAL, 1) except Exception as e: current_app.logger.error(e) # 保存错误的时候直接就返回了,因为下面的逻辑都无法保证了 return jsonify(errno=RET.DBERR, errmsg='短信验证码保存异常') # 发送短信验证码 # use celery, 第三方的错误出现错误不能保证,所以也需要进行捕获, result = send_sms.delay( phone_num, [sms_code, int(constants.SMS_CODE_REDIS_EXPIRES / 60)], 1) # the return'result is a async_process object # print(result.id) # through get() method to obtain celery async_process resoult # the behavior of get() method is Blocking behavior(阻塞行为) ,会等到拿到结果之后再返回 # get 方法也可以接受参数timeout,超时时间,超过超时时间之后还拿不到结果,则返回 # ret = result.get() # print(ret) # 0 stands for success # 发送成功 return jsonify(errno=RET.OK, errmsg='发送成功')