Flask项目(三)定义登录装饰器、图片服务、缓存机制、celery
作者:互联网
Flask项目
定义登录装饰器
utils\commons.py
from werkzeug.routing import BaseConverter
from flask import session, jsonify, g
from ihome.utils.response_code import RET
import functools
# 定义的验证登录状态的装饰器
def login_required(view_func):
# wraps函数的作用是将wrapper内层函数的属性设置为被装饰函数view_func的属性
@functools.wraps(view_func) # 不改变被装饰函数的属性相关
def wrapper(*args, **kwargs):
# 判断用户的登录状态
user_id = session.get("user_id")
# 如果用户是登录的, 执行视图函数
if user_id is not None:
# 将user_id保存到g对象中,在视图函数中可以通过g对象获取保存数据
g.user_id = user_id
return view_func(*args, **kwargs)
else:
# 如果未登录,返回未登录的信息
return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
return wrapper
redis文档
http://redis-py.readthedocs.io/en/latest/#indices-and-tables
http://redisdoc.com/index.html
图片服务
1)保存到程序本地,扩容(磁盘满的问题)
2)备份的问题
3)多机存储的问题
4) 用户A 图片A
用户B 图片B
图片A 与 图片B 是同一张图片,会保存两次,浪费空间
5)用户A a.jpg
用户B a.jpg
同名图片,但不是同一张,后上传的会覆盖掉之前的内容
文件存储解决方案:
1) 自己搭建文件存储系统 FastDFS 快速分布式文件存储系统 HDFS Hadoop分布式文件系统
2) 选择第三方服务 七牛云存储 www.qiniu.com
封装七牛方法
utils\image_storage.py
# -*- coding: utf-8 -*-
from qiniu import Auth, put_data, etag, urlsafe_base64_encode
import qiniu.config
# 需要填写你的 Access Key 和 Secret Key
access_key = 'uzc59bVURbUbazey9vrexXKocNKBUN8NuLijk57N'
secret_key = '-9lenw28jU2REojvGkcsEPWk5Nm9V2HIVqb5Nkts'
def storage(file_data):
"""
上传文件到七牛
:param file_data: 要上传的文件数据
:return:
"""
# 构建鉴权对象
q = Auth(access_key, secret_key)
# 要上传的空间
bucket_name = 'ihome'
# 生成上传 Token,可以指定过期时间等
token = q.upload_token(bucket_name, None, 3600)
ret, info = put_data(token, None, file_data)
# print(info)
# print("*"*10)
# print(ret)
if info.status_code == 200:
# 表示上传成功, 返回文件名
return ret.get("key")
else:
# 上传失败
raise Exception("上传七牛失败")
if __name__ == '__main__':
with open("./1.png", "rb") as f:
file_data = f.read()
storage(file_data)
profile.py
# coding:utf-8
from . import api
from ihome.utils.commons import login_required
from flask import g, current_app, jsonify, request
from ihome.utils.response_code import RET
from ihome.utils.image_storage import storage
from ihome.models import User
from ihome import db, constants
@api.route("/users/avatar", methods=["POST"])
@login_required
def set_user_avatar():
"""设置用户的头像
参数: 图片(多媒体表单格式) 用户id (g.user_id)
"""
# 装饰器的代码中已经将user_id保存到g对象中,所以视图中可以直接读取
user_id = g.user_id
# 获取图片
image_file = request.files.get("avatar")
if image_file is None:
return jsonify(errno=RET.PARAMERR, errmsg="未上传图片")
image_data = image_file.read()
# 调用七牛上传图片, 返回文件名
try:
file_name = storage(image_data)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.THIRDERR, errmsg="上传图片失败")
# 保存文件名到数据库中
try:
User.query.filter_by(id=user_id).update({"avatar_url": file_name})
db.session.commit()
except Exception as e:
db.session.rollback()
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="保存图片信息失败")
avatar_url = constants.QINIU_URL_DOMAIN + file_name
# 保存成功返回
return jsonify(errno=RET.OK, errmsg="保存成功", data={"avatar_url": avatar_url})
前端部分
profile.py
function showSuccessMsg() {
$('.popup_con').fadeIn('fast', function() {
setTimeout(function(){
$('.popup_con').fadeOut('fast',function(){});
},1000)
});
}
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
$(document).ready(function () {
$("#form-avatar").submit(function (e) {
// 阻止表单的默认行为
e.preventDefault();
// 利用jquery.form.min.js提供的ajaxSubmit对表单进行异步提交
$(this).ajaxSubmit({
url: "/api/v1.0/users/avatar",
type: "post",
dataType: "json",
headers: {
"X-CSRFToken": getCookie("csrf_token")
},
success: function (resp) {
if (resp.errno == "0") {
// 上传成功
var avatarUrl = resp.data.avatar_url;
$("#user-avatar").attr("src", avatarUrl);
} else {
alert(resp.errmsg);
}
}
})
})
})
城区数据下拉列表(缓存)
house.py
# coding:utf-8
from . import api
from ihome.utils.commons import login_required
from flask import g, current_app, jsonify, request
from ihome.utils.response_code import RET
from ihome.models import Area
from ihome import db, constants, redis_store
import json
@api.route("/areas")
def get_area_info():
"""获取城区信息"""
# 尝试从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:
# 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字符串
resp_dict = dict(errno=RET.OK, errmsg="OK", data=area_dict_li)
resp_json = json.dumps(resp_dict)
# 将数据保存到redis中
try:
redis_store.setex("area_info", constants.AREA_INFO_REDIS_CACHE_EXPIRES, resp_json)
except Exception as e:
current_app.logger.error(e)
return resp_json, 200, {"Content-Type": "application/json"}
前端部分
newhouse.js
前端js模板 art-template
https://aui.github.io/art-template/zh-cn/index.html
1.下载template文件
2.html文件引入
<script src="/static/js/template.js"></script>
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
$(document).ready(function(){
// 向后端获取城区信息
$.get("/api/v1.0/areas", function (resp) {
if (resp.errno == "0") {
var areas = resp.data;
// for (i=0; i<areas.length; i++) {
// var area = areas[i];
// $("#area-id").append('<option value="'+ area.aid +'">'+ area.aname +'</option>');
// }
// 使用js模板
var html = template("areas-tmpl", {areas: areas})
$("#area-id").html(html);
} else {
alert(resp.errmsg);
}
}, "json");
$("#form-house-info").submit(function (e) {
e.preventDefault();
// 处理表单数据
var data = {};
$("#form-house-info").serializeArray().map(function(x) { data[x.name]=x.value });
// 收集设置id信息
var facility = [];
$(":checked[name=facility]").each(function(index, x){facility[index] = $(x).val()});
data.facility = facility;
// 向后端发送请求
$.ajax({
url: "/api/v1.0/houses/info",
type: "post",
contentType: "application/json",
data: JSON.stringify(data),
dataType: "json",
headers: {
"X-CSRFToken": getCookie("csrf_token")
},
success: function (resp) {
if (resp.errno == "4101") {
// 用户未登录
location.href = "/login.html";
} else if (resp.errno == "0") {
// 隐藏基本信息表单
$("#form-house-info").hide();
// 显示图片表单
$("#form-house-image").show();
// 设置图片表单中的house_id
$("#house-id").val(resp.data.house_id);
} else {
alert(resp.errmsg);
}
}
})
});
$("#form-house-image").submit(function (e) {
e.preventDefault();
$(this).ajaxSubmit({
url: "/api/v1.0/houses/image",
type: "post",
dataType: "json",
headers: {
"X-CSRFToken": getCookie("csrf_token"),
},
success: function (resp) {
if (resp.errno == "4101") {
location.href = "/login.html";
} else if (resp.errno == "0") {
$(".house-image-cons").append('<img src="' + resp.data.image_url +'">');
} else {
alert(resp.errmsg);
}
}
})
})
})
用户认证相关
profile.py
@api.route("/users/name", methods=["PUT"])
@login_required
def change_user_name():
"""修改用户名"""
# 使用了login_required装饰器后,可以从g对象中获取用户user_id
user_id = g.user_id
# 获取用户想要设置的用户名
req_data = request.get_json()
if not req_data:
return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")
name = req_data.get("name") # 用户想要设置的名字
if not name:
return jsonify(errno=RET.PARAMERR, errmsg="名字不能为空")
# 保存用户昵称name,并同时判断name是否重复(利用数据库的唯一索引)
try:
User.query.filter_by(id=user_id).update({"name": name})
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
return jsonify(errno=RET.DBERR, errmsg="设置用户错误")
# 修改session数据中的name字段
session["name"] = name
return jsonify(errno=RET.OK, errmsg="OK", data={"name": name})
@api.route("/user", methods=["GET"])
@login_required
def get_user_profile():
"""获取个人信息"""
user_id = g.user_id
# 查询数据库获取个人信息
try:
user = User.query.get(user_id)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="获取用户信息失败")
if user is None:
return jsonify(errno=RET.NODATA, errmsg="无效操作")
return jsonify(errno=RET.OK, errmsg="OK", data=user.to_dict())
@api.route("/users/auth", methods=["GET"])
@login_required
def get_user_auth():
"""获取用户的实名认证信息"""
user_id = g.user_id
# 在数据库中查询信息
try:
user = User.query.get(user_id)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="获取用户实名信息失败")
if user is None:
return jsonify(errno=RET.NODATA, errmsg="无效操作")
return jsonify(errno=RET.OK, errmsg="OK", data=user.auth_to_dict())
@api.route("/users/auth", methods=["POST"])
@login_required
def set_user_auth():
"""保存实名认证信息"""
user_id = g.user_id
# 获取参数
req_data = request.get_json()
if not req_data:
return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
real_name = req_data.get("real_name") # 真实姓名
id_card = req_data.get("id_card") # 身份证号
# 参数校验
if not all([real_name, id_card]):
return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
# 保存用户的姓名与身份证号
try:
User.query.filter_by(id=user_id, real_name=None, id_card=None)\
.update({"real_name": real_name, "id_card": id_card})
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
return jsonify(errno=RET.DBERR, errmsg="保存用户实名信息失败")
return jsonify(errno=RET.OK, errmsg="OK")
发布房源
house.py
# coding:utf-8
from . import api
from ihome.utils.commons import login_required
from flask import g, current_app, jsonify, request
from ihome.utils.response_code import RET
from ihome.models import Area, House, Facility, HouseImage
from ihome import db, constants, redis_store
from ihome.utils.commons import login_required
from ihome.utils.image_storage import storage
import json
@api.route("/areas")
def get_area_info():
"""获取城区信息"""
# 尝试从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:
# 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字符串
resp_dict = dict(errno=RET.OK, errmsg="OK", data=area_dict_li)
resp_json = json.dumps(resp_dict)
# 将数据保存到redis中
try:
redis_store.setex("area_info", constants.AREA_INFO_REDIS_CACHE_EXPIRES, resp_json)
except Exception as e:
current_app.logger.error(e)
return resp_json, 200, {"Content-Type": "application/json"}
@api.route("/houses/info", methods=["POST"])
@login_required
def save_house_info():
"""保存房屋的基本信息
前端发送过来的json数据
{
"title":"",
"price":"",
"area_id":"1",
"address":"",
"room_count":"",
"acreage":"",
"unit":"",
"capacity":"",
"beds":"",
"deposit":"",
"min_days":"",
"max_days":"",
"facility":["7","8"]
}
"""
# 获取数据
user_id = g.user_id
house_data = request.get_json()
title = house_data.get("title") # 房屋名称标题
price = house_data.get("price") # 房屋单价
area_id = house_data.get("area_id") # 房屋所属城区的编号
address = house_data.get("address") # 房屋地址
room_count = house_data.get("room_count") # 房屋包含的房间数目
acreage = house_data.get("acreage") # 房屋面积
unit = house_data.get("unit") # 房屋布局(几室几厅)
capacity = house_data.get("capacity") # 房屋容纳人数
beds = house_data.get("beds") # 房屋卧床数目
deposit = house_data.get("deposit") # 押金
min_days = house_data.get("min_days") # 最小入住天数
max_days = house_data.get("max_days") # 最大入住天数
# 校验参数
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:
current_app.logger.error(e)
return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
# 判断城区id是否存在
try:
area = Area.query.get(area_id)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="数据库异常")
if area is None:
return jsonify(errno=RET.NODATA, 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
)
# 处理房屋的设施信息
facility_ids = house_data.get("facility")
# 如果用户勾选了设施信息,再保存数据库
if facility_ids:
# ["7","8"]
try:
# select * from ih_facility_info where id in []
facilities = Facility.query.filter(Facility.id.in_(facility_ids)).all()
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="数据库异常")
if facilities:
# 表示有合法的设施数据
# 保存设施数据
house.facilities = facilities
try:
db.session.add(house)
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
return jsonify(errno=RET.DBERR, errmsg="保存数据失败")
# 保存数据成功
return jsonify(errno=RET.OK, errmsg="OK", data={"house_id": house.id})
@api.route("/houses/image", methods=["POST"])
@login_required
def save_house_image():
"""保存房屋的图片
参数 图片 房屋的id
"""
image_file = request.files.get("house_image")
house_id = request.form.get("house_id")
if not all([image_file, house_id]):
return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
# 判断house_id正确性
try:
house = House.query.get(house_id)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="数据库异常")
if house is None: # if not house:
return jsonify(errno=RET.NODATA, errmsg="房屋不存在")
image_data = image_file.read()
# 保存图片到七牛中
try:
file_name = storage(image_data)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.THIRDERR, errmsg="保存图片失败")
# 保存图片信息到数据库中
house_image = HouseImage(house_id=house_id, url=file_name)
db.session.add(house_image)
# 处理房屋的主图片
if not house.index_image_url:
house.index_image_url = file_name
db.session.add(house)
try:
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
return jsonify(errno=RET.DBERR, errmsg="保存图片数据异常")
image_url = constants.QINIU_URL_DOMAIN + file_name
return jsonify(errno=RET.OK, errmsg="OK", data={"image_url": image_url})
map 函数
li1 = [1, 2, 3, 4]
# li2 = [2, 3, 4, 5]
li2 = [2, 3]
def add(num1, num2):
return num1+num2
ret = map(add, li1, li2)
def add_self(num):
return num+2
# ret = map(add_self, li1)
# print(ret) # python2 中直接返回列表
print(list(ret)) # python3 中返回对象,需要通过list拿到具体的数据值
celery 基本使用
# coding:utf-8
from celery import Celery
from ihome.libs.yuntongxun.sms import CCP
# 定义celery对象
celery_app = Celery("ihome", broker="redis://127.0.0.1:6379/1")
@celery_app.task
def send_sms(to, datas, temp_id):
"""发送短信的异步任务"""
ccp = CCP()
ccp.send_template_sms(to, datas, temp_id)
# celery开启的命令
# celery -A ihome.tasks.task_sms worker -l info
# # GET /api/v1.0/sms_codes/<mobile>?image_code=xxxx&image_code_id=xxxx
# @api.route("/sms_codes/<re(r'1[34578]\d{9}'):mobile>")
# def get_sms_code(mobile):
# """获取短信验证码"""
# # 获取参数
# image_code = request.args.get("image_code")
# image_code_id = request.args.get("image_code_id")
#
# # 校验参数
# if not all([image_code_id, image_code]):
# # 表示参数不完整
# 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数据库异常")
#
# # 判断图片验证码是否过期
# 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)
#
# # 与用户填写的值进行对比
# if real_image_code.lower() != image_code.lower():
# # 表示用户填写错误
# return jsonify(errno=RET.DATAERR, errmsg="图片验证码错误")
#
# # 判断对于这个手机号的操作,在60秒内有没有之前的记录,如果有,则认为用户操作频繁,不接受处理
# try:
# send_flag = redis_store.get("send_sms_code_%s" % mobile)
# except Exception as e:
# current_app.logger.error(e)
# else:
# if send_flag is not None:
# # 表示在60秒内之前有过发送的记录
# return jsonify(errno=RET.REQERR, errmsg="请求过于频繁,请60秒后重试")
#
# # 判断手机号是否存在
# try:
# user = User.query.filter_by(mobile=mobile).first()
# except Exception as e:
# current_app.logger.error(e)
# else:
# if user is not None:
# # 表示手机号已存在
# return jsonify(errno=RET.DATAEXIST, errmsg="手机号已存在")
#
# # 如果手机号不存在,则生成短信验证码
# sms_code = "%06d" % random.randint(0, 999999)
#
# # 保存真实的短信验证码
# try:
# redis_store.setex("sms_code_%s" % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
# # 保存发送给这个手机号的记录,防止用户在60s内再次出发发送短信的操作
# redis_store.setex("send_sms_code_%s" % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
# except Exception as e:
# current_app.logger.error(e)
# return jsonify(errno=RET.DBERR, errmsg="保存短信验证码异常")
#
# # 发送短信
# try:
# ccp = CCP()
# result = ccp.send_template_sms(mobile, [sms_code, int(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:
# # 发送成功
# return jsonify(errno=RET.OK, errmsg="发送成功")
# else:
# return jsonify(errno=RET.THIRDERR, errmsg="发送失败")
# GET /api/v1.0/sms_codes/<mobile>?image_code=xxxx&image_code_id=xxxx
@api.route("/sms_codes/<re(r'1[34578]\d{9}'):mobile>")
def get_sms_code(mobile):
"""获取短信验证码"""
# 获取参数
image_code = request.args.get("image_code")
image_code_id = request.args.get("image_code_id")
# 校验参数
if not all([image_code_id, image_code]):
# 表示参数不完整
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数据库异常")
# 判断图片验证码是否过期
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)
# 与用户填写的值进行对比
if real_image_code.lower() != image_code.lower():
# 表示用户填写错误
return jsonify(errno=RET.DATAERR, errmsg="图片验证码错误")
# 判断对于这个手机号的操作,在60秒内有没有之前的记录,如果有,则认为用户操作频繁,不接受处理
try:
send_flag = redis_store.get("send_sms_code_%s" % mobile)
except Exception as e:
current_app.logger.error(e)
else:
if send_flag is not None:
# 表示在60秒内之前有过发送的记录
return jsonify(errno=RET.REQERR, errmsg="请求过于频繁,请60秒后重试")
# 判断手机号是否存在
try:
user = User.query.filter_by(mobile=mobile).first()
except Exception as e:
current_app.logger.error(e)
else:
if user is not None:
# 表示手机号已存在
return jsonify(errno=RET.DATAEXIST, errmsg="手机号已存在")
# 如果手机号不存在,则生成短信验证码
sms_code = "%06d" % random.randint(0, 999999)
# 保存真实的短信验证码
try:
redis_store.setex("sms_code_%s" % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
# 保存发送给这个手机号的记录,防止用户在60s内再次出发发送短信的操作
redis_store.setex("send_sms_code_%s" % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="保存短信验证码异常")
# 发送短信
# 使用celery异步发送短信, delay函数调用后立即返回
send_sms.delay(mobile, [sms_code, int(constants.SMS_CODE_REDIS_EXPIRES/60)], 1)
# 返回值
# 发送成功
return jsonify(errno=RET.OK, errmsg="发送成功")
房屋管理
from . import api
from flask import g, current_app, jsonify, request, session
from ihome.utils.response_code import RET
from ihome.models import Area, House, Facility, HouseImage, User, Order
from ihome import db, constants, redis_store
from ihome.utils.commons import login_required
from ihome.utils.image_storage import storage
from datetime import datetime
import json
@api.route("/user/houses", methods=["GET"])
@login_required
def get_user_houses():
"""获取房东发布的房源信息条目"""
user_id = g.user_id
try:
# House.query.filter_by(user_id=user_id)
user = User.query.get(user_id)
houses = user.houses
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="获取数据失败")
# 将查询到的房屋信息转换为字典存放到列表中
houses_list = []
if houses:
for house in houses:
houses_list.append(house.to_basic_dict())
return jsonify(errno=RET.OK, errmsg="OK", data={"houses": houses_list})
@api.route("/houses/index", methods=["GET"])
def get_house_index():
"""获取主页幻灯片展示的房屋基本信息"""
# 从缓存中尝试获取数据
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")
# 因为redis中保存的是json字符串,所以直接进行字符串拼接返回
return '{"errno":0, "errmsg":"OK", "data":%s}' % ret, 200, {"Content-Type": "application/json"}
else:
try:
# 查询数据库,返回房屋订单数目最多的5条数据
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())
# 将数据转换为json,并保存到redis缓存
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 '{"errno":0, "errmsg":"OK", "data":%s}' % json_houses, 200, {"Content-Type": "application/json"}
@api.route("/houses/index", methods=["GET"])
def get_house_index():
"""获取主页幻灯片展示的房屋基本信息"""
# 从缓存中尝试获取数据
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")
# 因为redis中保存的是json字符串,所以直接进行字符串拼接返回
return '{"errno":0, "errmsg":"OK", "data":%s}' % ret, 200, {"Content-Type": "application/json"}
else:
try:
# 查询数据库,返回房屋订单数目最多的5条数据
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())
# 将数据转换为json,并保存到redis缓存
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 '{"errno":0, "errmsg":"OK", "data":%s}' % json_houses, 200, {"Content-Type": "application/json"}
@api.route("/houses/<int:house_id>", methods=["GET"])
def get_house_detail(house_id):
"""获取房屋详情"""
# 前端在房屋详情页面展示时,如果浏览页面的用户不是该房屋的房东,则展示预定按钮,否则不展示,
# 所以需要后端返回登录用户的user_id
# 尝试获取用户登录的信息,若登录,则返回给前端登录用户的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:
current_app.logger.error(e)
ret = None
if ret:
current_app.logger.info("hit house info redis")
return '{"errno":"0", "errmsg":"OK", "data":{"user_id":%s, "house":%s}}' % (user_id, ret), \
200, {"Content-Type": "application/json"}
# 查询数据库
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.DATAERR, errmsg="数据出错")
# 存入到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":{"user_id":%s, "house":%s}}' % (user_id, json_house), \
200, {"Content-Type": "application/json"}
return resp
前端部分
detail.js
function hrefBack() {
history.go(-1);
}
// 解析提取url中的查询字符串参数
function decodeQuery(){
var search = decodeURI(document.location.search);
return search.replace(/(^\?)/, '').split('&').reduce(function(result, item){
values = item.split('=');
result[values[0]] = values[1];
return result;
}, {});
}
$(document).ready(function(){
// 获取详情页面要展示的房屋编号
var queryData = decodeQuery();
var houseId = queryData["id"];
// 获取该房屋的详细信息
$.get("/api/v1.0/houses/" + houseId, function(resp){
if ("0" == resp.errno) {
$(".swiper-container").html(template("house-image-tmpl", {img_urls:resp.data.house.img_urls, price:resp.data.house.price}));
$(".detail-con").html(template("house-detail-tmpl", {house:resp.data.house}));
// resp.user_id为访问页面用户,resp.data.user_id为房东
if (resp.data.user_id != resp.data.house.user_id) {
$(".book-house").attr("href", "/booking.html?hid="+resp.data.house.hid);
$(".book-house").show();
}
var mySwiper = new Swiper ('.swiper-container', {
loop: true,
autoplay: 2000,
autoplayDisableOnInteraction: false,
pagination: '.swiper-pagination',
paginationType: 'fraction'
});
}
})
})
myhouse.js
$(document).ready(function(){
// 对于发布房源,只有认证后的用户才可以,所以先判断用户的实名认证状态
$.get("/api/v1.0/users/auth", function(resp){
if ("4101" == resp.errno) {
// 用户未登录
location.href = "/login.html";
} else if ("0" == resp.errno) {
// 未认证的用户,在页面中展示 "去认证"的按钮
if (!(resp.data.real_name && resp.data.id_card)) {
$(".auth-warn").show();
return;
}
// 已认证的用户,请求其之前发布的房源信息
$.get("/api/v1.0/user/houses", function(resp){
if ("0" == resp.errno) {
$("#houses-list").html(template("houses-list-tmpl", {houses:resp.data.houses}));
} else {
$("#houses-list").html(template("houses-list-tmpl", {houses:[]}));
}
});
}
});
})
标签:缓存,return,Flask,house,celery,errno,data,id,errmsg 来源: https://blog.csdn.net/qq_27251475/article/details/121305308