示例#1
0
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
示例#2
0
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"}
示例#3
0
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"}
示例#4
0
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
示例#5
0
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='发送成功')