def generate_image_code(image_code_id): """ 生成图片验证码 1. 调用captcha 扩展包生成图片验证码,name,text, image 2. 在服务器保存图片验证码内容,在缓存redis数据库中存储 3. 使用响应对象返回前端图片验证码 :param image_code_id: :return: """ # 生成图片验证码,调用captcha 扩展包 name, text, image = captcha.generate_captcha() # 在服务器redis缓存中存储图片验证码的内容,指定过期时间 try: redis_store.setex('ImageCode_' + image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text) except Exception as e: # 日志记录 current_app.logger.error(e) # jsonify 序列化数据 return jsonify(errno=RET.DBERR, errmsg='保存图片验证码失败') # 返回前图片验证码,需要使用响应对象 # finally是无论是否有异常,都会被执行,else如未异常执行 else: response = make_response(image) # 设置响应的数据类型 response.headers['Content-Type'] = 'image/jpg' # 返回前端图片验证码 return response
def get_house_detail(house_id): """ 获取房屋详情信息:缓存----磁盘----缓存 1/获取参数,user_id,把用户分为两类,登陆用户/未登陆用户 user_id = session.get('user_id','-1') 2/校验house_id参数 3/尝试从redis缓存中获取房屋信息 4/校验结果,如果有数据, 5/查询mysql数据库 6/调用模型类的to_full_dict(),进行异常处理 7/序列化数据 8/存储到redis缓存中 9/返回结果 :return: """ # 使用请求上下文对象session,从redis中获取用户身份信息,如未登陆,默认给-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).decode(encoding='utf-8') except Exception as e: current_app.logger.error(e) ret = None # 判断获取结果 if ret: current_app.logger.info('hit house detail info redis') return '{"errno":0,"errmsg":"OK","data":{"user_id":%s,"house":%s}}' % ( user_id, ret) # 查询mysql数据库 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='无房屋数据') # 调用模型类中方法,获取房屋详情信息 try: house_data = house.to_full_dict() except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg='获取房屋详情信息异常') # 序列化数据 house_json = json.dumps(house_data) # 把房屋详情数据存入缓存中 try: redis_store.setex('house_info_%s' % house_id, constants.HOUSE_DETAIL_REDIS_EXPIRE_SECOND, house_json) except Exception as e: current_app.logger.error(e) # 返回结果 resp = '{"errno":0,"errmsg":"OK","data":{"user_id":%s,"house":%s}}' % ( user_id, house_json) return resp
def get_houses_index(): """ 项目首页信息:缓存----磁盘----缓存 1/尝试从redis缓存中获取房屋信息 2/判断获取结果,如果有数据,记录访问时间,直接返回结果 3/查询mysql数据库 4/默认按照房屋成交量进行查询, houses = House.query.order_by(House.order_count.desc()).limit(5) 5/判断查询结果 6/定义列表,遍历查询结果,添加数据, 7/判断是否设置主图片,如未设置主图片默认不添加 8/序列化房屋数据 9/存入到缓存中, 10/返回结果 :return: """ # 尝试从redis获取房屋首页幻灯片信息 try: ret = redis_store.get('home_page_data') except Exception as e: current_app.logger.error(e) ret = None # 如果有数据,记录访问缓存数据的时间,直接返回房屋信息 if ret: current_app.logger.info('hit house index info redis') return '{"errno":0,"errmsg":"OK","data":%s}' % ret # 查询mysql数据库,获取房屋信息,默认按照房屋成交量进行倒叙查询 try: 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='查询房屋信息失败') # 校验查询结果 if not houses: return jsonify(errno=RET.NODATA, errmsg='无房屋数据') # 定义列表,遍历查询结果 houses_list = [] for house in houses: # 判断房屋主图片如未设置,默认不添加数据 if not house.index_image_url: continue houses_list.append(house.to_basic_dict()) # 序列化数据 houses_json = json.dumps(houses_list) # 把房屋数据存入到redis缓存中 try: redis_store.setex('home_page_data', constants.HOME_PAGE_DATA_REDIS_EXPIRES, houses_json) except Exception as e: current_app.logger.error(e) # 返回结果 resp = '{"errno":0,"errmsg":"Ok","data":%s}' % houses_json return resp
def get_area_info(): """ 获取区域信息 首页区域信息加载----缓存数据库-----磁盘数据库----缓存数据库 1. 尝试从redis 数据库中获取缓存的区域信息 2. 如果获取过程发生异常,要把获取结果重新置为None值 3. 判断获取结果,如果有数据直接返回,可留下房屋缓存数据的日志信息 4. 查询mysql数据库,获取区域信息 5. 校验查询结果 6. 对查询结果进行保存,遍历查询结果,调用模型类实例方法,添加区域信息 7. 序列化数据,转为json,存入缓存中 8. 拼接字符串,直接返回区域信息的json数据 :return: """ # 先尝试从redis缓存中获取区域信息 try: ret = redis_store.get('area_info').decode(encoding='utf-8') except Exception as e: current_app.logger.error(e) # 把ret重新置为None值 ret = None # 判断获取结果 if ret: # 记录访问redis数据库房屋区域信息的时间 current_app.logger.info('hit area info redis') # 直接返回区域信息数据 return '{"errno":0, "errmsg":"OK", "data":%s}' % ret # 查询mysql数据库,获取区域信息 try: areas = Area.query.all() except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg='获取区域信息失败') # 判断查询结果 if not areas: return jsonify(errno=RET.NODATA, errmsg='无区域信息') # 定义列表存储查询结果 areas_list = [] # 遍历查询结果,调用模型类的实例方法,添加区域信息数据 for area in areas: areas_list.append(area.to_dict()) # 转为json字符串,准备存入缓存中 areas_json = json.dumps(areas_list) try: redis_store.setex('area_info', constants.AREA_INFO_REDIS_EXPIRES, areas_json) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg='缓存区域信息异常') # 返回区域信息的json数据 resp = '{"errno":0, "errmsg":"OK","data":%s}' % areas_json return resp
def send_sms_code(mobile): """ 发送短信:获取参数/校验参数/查询数据/返回结果 1. 获取参数,查询字符串的参数获取,mobile, text, id, request.args.get('text') 2. 校验参数,首先校验参数存在 3. 校验手机号,正则表达式,re.match(r'^1[]$',mobile) 4. 校验图片验证码:获取本地存储的真实图片验证码 5. 判断获取结果,如果图片验证码过期结束程序 6. 删除图片验证码 7. 比较图片验证码:统一转成小写比较图片验证码内容是否一致 8. 生成短信码: 使用random 模块随机数 9. 在本地保存短信验证码内容,判断用户是否已注册 10. 调用云通讯发送信息: 使用异常进行处理 11. 保存云通讯的发送结果,判断是否发送成功 12. 返回前端结果 :param modile: :return: """ # 获取参数, mobile, text, id image_code = request.args.get('text') image_code_id = request.args.get('id') # 校验参数存在 # any, all 方法判断所有参数全部存在 if not all([mobile, image_code, image_code_id]): return jsonify(errno=RET.PARAMERR, errmsg='参数缺失') # 检验手机号,使用正则模块 if not re.match(r'1[345789]\d{9}$', mobile): return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误') # 校验图片验证码,获取本地存储的真实图片验证码 try: real_image_code = redis_store.get('ImageCode_' + image_code_id) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg='查询图片验证码异常') # 判断获取结果 if not real_image_code: return jsonify(errno=RET.NODATA, errmsg='图片验证码过期') # 图片验证码只能获取一次,无论是否获取到,都必须删除图片验证码 try: redis_store.delete('ImageCode_' + image_code_id) except Exception as e: current_app.logger.error(e) # 比较图片验证码内容是否一致 if real_image_code.lower() != image_code.lower(): return jsonify(errno=RET.DATAERR, errmsg='图片验证码错误') # 生成短信随机码,使用随机数模块,生成六位数 sms_code = '%06d' % random.randint(1, 999999) # 保存短信验证码 try: redis_store.setex('SMSCode_' + mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg='保存短信验证码失败') # 写注册的时候在使用 # # 判断用户是否已注册 # try: # user = User.query.filter_by(mobile=mobile).first() # except Exception as e: # current_app.logger.error(e) # return jsonify(errno=RET.DBERR,errmsg='查询用户信息异常') # else: # # 判断查询结果,用户是否注册 # if user is not None: # return jsonify(errno=RET.DATAEXIST, errmsg='手机号已注册') # 发送短信,调用云通讯接口 try: # 实例化对象 ccp = sms.CCP() # 调用云通讯发送短信方法 result = ccp.send_template_sms( mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES / 60], 1) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.THIRDERR, errmsg='发送短信异常') # 判断发送结果 # if result ==0: # 表达式判断,变量写在后面 if 0 == result: return jsonify(errno=RET.OK, errmsg='发送成功') else: return jsonify(errno=RET.THIRDERR, errmsg='发送失败')
def get_houses_list(): """ 房屋列表页: 获取参数/校验参数/查询数据/返回结果 缓存----磁盘----缓存 1/获取参数,area_id,start_date_str,end_date_str,sort_key,page 2/参数处理,sort_key给默认值,默认按照房屋发布时间进行排序,page默认加载第一页数据 3/判断如果有日期参数,对日期进行格式化处理,datetime模块 4/确认用户选择的开始日期必须小于等于结束结束日期,至少预定1天 5/对页数进行格式化,page = int(page) 6/尝试从redis中获取房屋列表信息,每页数据里存储多条数据,需要使用hash数据类型 ret = redis_store.hget('houses_%s_%s_%s_%s' % (area_id,start_date_str_end_date_str,sort_key)) 7/如果有数据,记录访问房屋列表数据的信息,返回结果 8/需要查询mysql数据库, 9/定义查询数据库的过滤条件,params_filter = []主要包括:区域信息/开始日期和结束日期 10/根据过滤条件查询数据库,按照booking成交量/价格price-inc,price-des/房屋发布时间new; houses = House.query.filter(*params_filter).order_by(House.create_time.desc()) 11/对查询结果进行分页,paginate分页返回的结果,包括总页数,房屋数据 hosues_page = houses.paginate(page,2,False) /False分页如果发生异常不报错 houses_list = houses_page.items (分页后的房屋数据) total_page = houses_page.pages (分页后的总页数) 12/遍历分页后的房屋数据,获取房屋的基本信息,需要调用模型类中的house_dict_list = to_basic_dict()方法 13/构造响应数据: resp = {"errno":0,"errmsg":"OK","data":{"houses":houses_dict_list,"total_page":total_page,"current_page":page}} 14/序列化数据,resp_json = json.dumps(resp) 15/存入缓存中,设置redis中房屋列表数据,判断用户请求的页数小于等于总页数,即请求的页数是有数据的 16/对多条数据往redis中存储,需要开启事务,确保数据的完整性和一致性, pip = redis_store.pipeline() pip.multi()/pip.hset(redis_key,page,resp_json)/pip.expire(redis_key,7200)/pip.execute() 17/返回结果 return resp_json :return: """ # 获取参数,当前接口都是可选参数 area_id = request.args.get('aid', '') start_date_str = request.args.get('sd', '') end_date_str = request.args.get('ed', '') sort_key = request.args.get('sk', 'new') # 如未传参默认new,房屋发布时间 page = request.args.get('p', '1') # 如未传参默认1,房屋列表页 # 首先对日期进行格式化 try: # 存储日期转换后的结果 start_date, end_date = None, None # 判断如有传入开始日期 if start_date_str: start_date = datetime.datetime.strptime(start_date_str, '%Y-%m-%d') # 判断如有传入结束日期: if end_date_str: end_date = datetime.datetime.strptime(end_date_str, '%Y-%m-%d') # 如果开始日期和结束日期都存在,判断开始日期小于等于结束日期,即订房的时间必须是1天 if start_date_str and end_date_str: # 断言代码放入try/except中,会被捕获, assert start_date <= end_date except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DATAERR, errmsg='日期格式错误') # 对页数进行格式化 try: page = int(page) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DATAERR, errmsg='页数格式错误') # 尝试从redis中获取房屋列表信息 try: # 键里包含区域信息/开始日期/结束日期/排序条件/分页 redis_key = 'houses_%s_%s_%s_%s_%s' % (area_id, start_date_str, end_date_str, sort_key, page) # 尝试获取redis缓存中的数据,指定键,属性 # ret = redis_store.hget(redis_key, page) ret = redis_store.get(redis_key).decode(encoding='utf-8') except Exception as e: current_app.logger.error(e) ret = None # 判断查询结果,如有数据直接返回 if ret: # 记录访问redis数据的时间 current_app.logger.info('hit houses list info redis') return ret # 查询mysql数据库 try: # 定义列表,存储查询房屋数据的过滤条件 params_filter = [] # 校验区域信息的存在 if area_id: # a = [1,3,5,7,9] # b = 5 # a.append(a == b) 添加的数据为true或false # 返回的结果是sqlalchemy的对象 params_filter.append(House.area_id == area_id) # 对日期进行处理,决定了房屋能否预定,判断用户如果选择了开始日期和结束日期 if start_date and end_date: # 查询有冲突的订单 conflict_orders = Order.query.filter( Order.begin_date <= end_date, Order.end_date >= start_date).all() # 遍历有冲突的订单,获取有冲突的房屋 conflict_houses_id = [order.house_id for order in conflict_orders] # 判断有冲突的房屋是否存在 if conflict_houses_id: # 存入过滤参数中,进行取反操作,获取所有不冲突的房屋 params_filter.append(House.id.notin_(conflict_houses_id)) # 如果用户只选择了开始日期 if start_date: # 查询开始日期有冲突的订单数据 conflict_orders = Order.query.filter( Order.end_date >= start_date).all() # 遍历有冲突的订单数据 conflict_houses_id = [order.house_id for order in conflict_orders] # 判断有冲突的房屋存在 if conflict_houses_id: params_filter.append(House.id.notin_(conflict_houses_id)) # 如果用户只选择了结束日期 if end_date: conflict_orders = Order.query.filter( Order.begin_date <= end_date).all() conflict_houses_id = [order.house_id for order in conflict_orders] if conflict_houses_id: params_filter.append(House.id.notin_(conflict_houses_id)) # 过滤条件已经完成,执行查询语句,获取房屋数据,进行排序查询 # 判断排序条件,按房屋成交排序查询 if 'booking' == sort_key: houses = House.query.filter(*params_filter).order_by( House.order_count.desc()) # 按照房屋价格进行排序 elif 'price-inc' == sort_key: houses = House.query.filter(*params_filter).order_by( House.price.asc()) elif 'prcie-des' == sort_key: houses = House.query.filter(*params_filter).order_by( House.price.desc()) # 如果用户未选择排序条件,默认按照房屋发布时间进行排序 else: houses = House.query.filter(*params_filter).order_by( House.create_time.desc()) # 对查询结果进行分页,page:页数,每页条目书,False分页出错,不会报错 houses_page = houses.paginate(page, constants.HOUSE_LIST_PAGE_CAPACITY, False) # 存储分页后的房屋数据 houses_list = houses_page.items # 存储分页后的总页数 total_page = houses_page.pages # 定义列表,存储分页后的数据 houses_dict_list = [] # 遍历分页后的数据,调用了模型类方法,获取房屋基本数据 for house in houses_list: houses_dict_list.append(house.to_basic_dict()) except Exception as e: current_app.logger.error(e) return jsonify(errno=RET.DBERR, errmsg='查询房屋列表信息失败') # 构造响应数据 resp = { "errno": 0, "errmsg": "OK", "data": { "houses": houses_dict_list, "total_page": total_page, "current_page": page } } # 序列化数据 resp_json = json.dumps(resp) # 判断用户请求的页数必须有数据 if page <= total_page: try: # 构造redis_key redis_key = 'houses_%s_%s_%s_%s_%s' % \ (area_id, start_date_str, end_date_str, sort_key, page) redis_store.setex(redis_key, constants.HOME_PAGE_DATA_REDIS_EXPIRES, resp_json) except Exception as e: current_app.logger.errno(e) # # 使用hash数据类型,对多条数据需要统一操作,使用事务 # pip = redis_store.pipeline() # try: # # 开启事务 # pip.multe() # # 设置数据 # pip.hset(redis_key, page, resp_json) # # 设置过期时间 # pip.expire(redis_key, constants.HOUSE_LIST_REDIS_EXPIRES) # # 执行事务 # pip.execute() # except Exception as e: # print(e) # current_app.logger.error(e) # 返回结果 return resp_json