示例#1
0
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
示例#2
0
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
示例#3
0
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
示例#4
0
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
示例#5
0
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='发送失败')
示例#6
0
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