Flask项目之手机端租房网站的实战开发(九)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/86302733
目录
一丶区县信息后端编写
1.定义视图函数
@api.route("/areas")
def get_area_info():
"""
获取区县信息
:return:
"""
pass
2.逻辑编写
- step1 从数据库中获取所有区县信息
try:
# 从数据库中获取所有区县信息
area_li = Area.query.all()
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="数据库异常")
- step2 在Area类中构建一个to_dict方法,将对象转换成字典,因为我们给前端传输数据是需要传输json格式数据的
def to_dict(self):
"""将对象转换为字典"""
data = {
"aid": self.id,
"aname": self.name
}
return data
- step3 遍历对象列表,调用每个对象中的to_dict方法,将返回的值添加到area_dict_li列表中
# 将对象转换为字典
area_dict_li = []
for area in area_li:
area_dict_li.append(area.to_dict())
- step4 返回正确响应数据
return jsonify(errno=RET.OK, errmsg="OK", data=area_dict_li)
3.测试接口
- step1 运行项目,打开Postman测试工具,向127.0.0.1:5000/api/v1.0/areas发送get请求
- step2 返回接口正确响应数据,因为数据库Area表没有数据,所以返回的响应数据为空
4.向数据库中ih_area_info以及ih_facility_info两张表插入测试数据
- step1 执行如下SQL语句
INSERT INTO `ih_area_info`(`name`) VALUES ('锦江区'),('青羊区'),('金牛区'),('武侯区'),('成华区'),('龙泉驿区'),('青白江区'),('新都区'),('温江区'),('郫都区'),('双流区'),('高新区'),('天府新区'),('新津县'),('大邑县'),('金堂县');
INSERT INTO `ih_facility_info`(`name`) VALUES('无线网络'),('热水淋浴'),('空调'),('暖气'),('允许吸烟'),('饮水设备'),('牙具'),('香皂'),('拖鞋'),('手纸'),('毛巾'),('沐浴露、洗发露'),('冰箱'),('洗衣机'),('电梯'),('允许做饭'),('允许带宠物'),('允许聚会'),('门禁系统'),('停车位'),('有线网络'),('电视'),('浴缸');
ih_area_info表
ih_facility_info表
- step2 再回到Postman中Send发送请求,显示出正确响应数据
二丶为区县信息补充缓存机制
1.为什么要补充缓存机制
- step1 在网站首页,需要频繁获取区域数据
- step2 在我的爱家中,发布房源也需要频繁获取区域数据
- step3 以及在房源列表,搜索栏也要频繁获取区域数据
2.分析,因为区县一般都是固定的,不会经常变化,搜索页面和主页是用户经常访问的地方,那么即我们后端接口以及数据库就会被大量访问,而且是在很短时间内,这样可能会出现异常问题,导致访问速度缓慢,所以完美解决方法就是使用缓存
3.具体实现流程
- step1 当用户访问区县信息时,就会调用后端我们写的get_area_info接口,之前写的代码是,每次访问都会从数据库中拿去数据,现在将这一块改变一下,先从redis数据中拿去数据库(这里选择redis数据库,因为是内存级的数据库)
- step2 如果redis数据库中有区域数据,直接返回给前端
- step3 当redis数据库中没有区域数据时,此时再去mysql数据库中进行数据获取,拿到的区域数据不会马上返回给前端,而是将拿到的数据保存到redis数据库中,最后才返回给前端
4.逻辑代码编写
思考:将数据保存到redis数据库中,此时需要思考,以怎么形式保存数据,保存哪些数据到redis数据库
实现:是将整个返回给前端正确响应数据全部以json格式的字符串保存
- step1 将数据转换为json字符串
resp_dict = dict(errno=RET.OK, errmsg="OK", data=area_dict_li)
resp_json_str = json.dumps(resp_dict)
- step2 将构建的json格式的字符串响应数据保存到redis数据库中, 并设置有效期
try:
redis_store.setex("area_info",constants.AREA_INFO_REDIS_CACHE_EXPIRES, resp_json_str)
except Exception as e:
current_app.logger.error(e)
- step3 返回构造响应头数据,设置Content-Type为json,默认的为html
return resp_json_str, 200, {"Content-Type":"application/json"}
- step4 调用接口一开始从redis数据库中拿去区域数据
try:
resp_json_str = redis_store.get("area_info")
except Exception as e:
current_app.logger.error(e)
else:
if resp_json_str is not None:
return resp_json_str, 200, {"Content-Type": "application/json"}
- step5 当redis数据库中获取的数据不为空时,往日志info中记录一句话,方便测试是从mysql 还是 redis 获取的区域数据
current_app.logger.info("Area data from redis")
5.测试redis缓存是否成功
- step1 运行项目
- step2 在Postman测试工具中向后端接口
第一次Send发送请求,查看程序运行日志,并没有显示我们定义日志信息
第二次Send发送请求,则显示我们定义的info日志信息,说明区域数据是从redis数据库中获取的
- step3 查看redis数据库,并获取area_info键的值
三丶缓存数据同步问题
问:怎么保证redis缓存的数据和mysql数据保持一致性?
第一种方式:mysql数据库维护人员在修改区域表数据时,将redis数据库key删除
第二种方式:就是我们这种简单暴力有效的方式,设置数据的有效期,让redis数据库来帮我们把数据进行删除
四丶完善后端用户模块
1.对profile模块中的update_name进行修改
- step1 修改路由请求方式
@api.route("/users/name", methods=["PUT"])
- step2 从g对象中获取用户id
user_id = g.user_id
- step3 获取前端请求中的参数
req_dict = request.get_json()
- step4 判断参数是否为空
if not req_dict:
return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")
- step5 获取用户修改的名字
name = req_dict.get("name")
- step6 判断用户是否输入用户名
if name is None:
return jsonify(errno=RET.PARAMERR, errmsg="名字不能为空")
- step7 将用户修改后的名字保存到数据库,需要注意的是这里不需要判断名字name是否重复,因为当初在创建数据库表字段name的时候设置了唯一索引
try:
User.query.filter_by(id=user_id).update({"name": name})
db.session.commit()
except Exception as e:
db.session.rollback()
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="保存用户名字失败")
- step8 因为在登录和注册接口编写时候最后都将name保存到session中,所以当用户修改name后,也需要将新的name进行session保存
session["name"] = name
- step9 最后返回正确响应
return jsonify(errno=RET.OK, errmsg="修改成功", data={"name": name})
2.获取个人信息在我的爱家中进行显示
- step1 定义视图函数
@api.route("/user", methods=["GET"])
@login_required
def get_user_profile():
- step2 获取用户id
user_id = g.user_id
- step3 根据用户id在数据库中查询个人信息
try:
user = User.query.get(user_id)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="获取用户信息失败")
- step4 判断用户对象是否为空
if User is None:
return jsonify(errno=RET.NODATA, errmsg="无效操作")
- step5 在models模块中构建一个to_dict方法,用于构建我们返回给前端的数据
def to_dict(self):
"""将对象转换为字典数据"""
user_dict = {
"user_id": self.id,
"name": self.name,
"mobile": self.mobile,
"avatar": constants.QINIU_URL_DOMAIN + self.avatar_url if self.avatar_url else "",
"create_time": self.create_time.strftime("%Y-%m-%d %H:%M:%S")
}
return user_dict
- step6 回到profile模块中,返回正确响应数据给前端
return jsonify(errno=RET.OK, errmsg="OK", data=user.to_dict())
3.获取用户的实名认证信息
- step1 定义视图函数
@api.route("/users/auth", methods=["GET"])
@login_required
def get_user_auth():
- step2 获取用户id
user_id = g.user_id
- step3 根据用户id在数据库中进行查询, 获取用户对象
try:
user = User.query.get(user_id)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="获取用户实名认证信息失败")
- step4 判断用户对象是否为空
if user is None:
return jsonify(errno=RET.NODATA, errmsg="无效操作")
- step5 在models模块中构建一个auth_to_dict方法,用于构建我们返回给前端的数据
def auth_to_dict(self):
"""将用户实名信息转换为字典数据"""
auth_dict = {
"user_id": self.id,
"real_name": self.real_name,
"id_card": self.id_card
}
return auth_dict
- step6 回到profile模块中,返回正确响应数据给前端
return jsonify(errno=RET.OK, errmsg="OK", data=user.auth_to_dict())
4.向数据库中保存用户实名认证信息
- step1 定义视图函数
@api.route("/users/auth", methods=["POST"])
@login_required
def set_user_auth():
- step2 获取用户id
user_id = g.user_id
- step3 获取前端发送请求中的参数
req_data = request.get_json()
- step4 判断参数是否为空
if not req_data:
return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
- step5 获取用户输入的真实姓名和身份证号
real_name = req_data.get("real_name")
id_card = req_data.get("id_card")
- step6 校验参数完整性
if not all([real_name,id_card]):
return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
- step7 将用户填写的真实姓名和身份证号保存到数据库中,这里在数据库进行数据更新是为什么将real_name和id_card默认为空,因为在后端来说,用户只能设置一次实名认证,当real_name和id_card为None时,才代用户是第一次进行认证,当获取的real_name和id_card不为空时,说明用户之前已经认证过了
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="保存用户实名信息失败")
- step8 向前端返回正确响应
return jsonify(errno=RET.OK, errmsg="OK")
五丶完善前端用户模块
1.在profile.html文件中进行如下修改
<form id="form-name" action="/api/profile/name" method="post">
2.在profile.js中进行如下编写
- step1 在个人信息栏显示用户信息
// 在页面加载是向后端查询用户的信息
$.get("/api/v1.0/user", function(resp){
// 当后端接口检验登录装饰器返回4101状态码,表示用户未登录,即跳转到登录页面
if (resp.errno == "4101") {
location.href = "/login.html";
}
// 后端返回正确响应码,将响应数据中的name填写到id = user-name的标签内容上
else if (resp.errno == "0") {
$("#user-name").val(resp.data.name);
// 头像链接存在则显示到src下
if (resp.data.avatar) {
$("#user-avatar").attr("src", resp.data.avatar);
}
}
}, "json");
- step2 将用户修改后的名字保存到数据库中
// 将用户修改后名字向后端进行发送
$("#form-name").submit(function(e){
e.preventDefault();
// 获取用户输入的名字
var name = $("#user-name").val();
if (!name) {
alert("请填写用户名!");
return;
}
$.ajax({
url:"/api/v1.0/users/name",
type:"PUT",
data: JSON.stringify({name: name}),
contentType: "application/json",
dataType: "json",
headers:{
"X-CSRFTOKEN":getCookie("csrf_token")
},
success: function (data) {
if (data.errno == "0") {
$(".error-msg").hide();
showSuccessMsg();
} else if (data.errno == "4001") {
$(".error-msg").show();
} else if (data.errno == "4101") {
location.href = "/login.html";
}
}
});
})
3.在我的爱家my.js中进行如下编写
$(document).ready(function(){
$.get("/api/v1.0/user", function(resp){
// 用户未登录
if (resp.errno == "4101") {
location.href = "/login.html";
}
// 查询到了用户的信息
else if (resp.errno == "0") {
$("#user-name").html(resp.data.name);
$("#user-mobile").html(resp.data.mobile);
if (resp.data.avatar) {
$("#user-avatar").attr("src", resp.data.avatar);
}
}
}, "json");
});
4.在实名认证auth.js中进行如下编写
- step1 当页面加载完毕时,想后端接口发送请求来获取用户的姓名和身份证
$(document).ready(function(){
// 查询用户的实名认证信息
$.get("/api/v1.0/users/auth", function(resp){
// 4101代表用户未登录
if (resp.errno == "4101") {
location.href = "/login.html";
} else if (resp.errno == "0") {
// 如果返回的数据中real_name与id_card不为null,表示用户有填写实名信息
if (resp.data.real_name && resp.data.id_card) {
$("#real-name").val(resp.data.real_name);
$("#id-card").val(resp.data.id_card);
// 给input添加disabled属性,禁止用户修改
$("#real-name").prop("disabled", true);
$("#id-card").prop("disabled", true);
// 隐藏提交保存按钮
$("#form-auth>input[type=submit]").hide();
}
} else {
alert(resp.errmsg);
}
}, "json");
- step2 当页面加载完毕时,如果用户已经进行了实名认证,那么就不显示保存按钮以及对输入框进行禁止修改
// 管理实名信息表单的提交行为
$("#form-auth").submit(function(e){
e.preventDefault();
// 如果用户没有填写完整,展示错误信息
var realName = $("#real-name").val();
var idCard = $("#id-card").val();
if (realName == "" || idCard == "") {
$(".error-msg").show();
}
// 将表单的数据转换为json字符串
var data = {
real_name: realName,
id_card: idCard
};
var jsonData = JSON.stringify(data);
// 向后端发送请求
$.ajax({
url:"/api/v1.0/users/auth",
type:"post",
data: jsonData,
contentType: "application/json",
dataType: "json",
headers: {
"X-CSRFTOKEN": getCookie("csrf_token")
},
success: function (resp) {
if (resp.errno == "0") {
$(".error-msg").hide();
// 显示保存成功的提示信息
showSuccessMsg();
$("#real-name").prop("disabled", true);
$("#id-card").prop("disabled", true);
$("#form-auth>input[type=submit]").hide();
}
}
});
})
5.当用户进行实名制后,那么在我的房源页面,就不应该显示去实名认证按钮
- step1 实名制之前显示界面
- step2 在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;
}
}
})
});
- step3 实名制之后显示页面
六丶测试用户模块中个人信息栏,我的爱家,实名认证
1.个人信息栏测试
- step1 登录网站,进入个人信息栏,显示如下
- step2 当修改用户名后,点击保存,显示保存成功提示
2.我的爱家栏测试,成功显示出用户头像,用户名以及手机号
3.用户实名认证栏测试
- step1 首次进行实名认证,界面显示如下
- step2 当未填写姓名和身份证号时,出现如下显示
- step3 当输入完整信息后,会显示保存成功,出现如下界面
- step4 查看数据库信息
- step5 此号码已经实名认证成功,再次进入实名认证,则显示如下界面
七丶效果动图展示
Flask项目之手机端租房网站的实战开发(九)的更多相关文章
- Flask项目之手机端租房网站的实战开发(三)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...
- Flask项目之手机端租房网站的实战开发(一)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 一丶项目介绍 产品:关于手机移动端的租房网站 角色:在这个产品中用户包括房东与房客 功能:房东可以在这个平台发布自己的房屋,房客可 ...
- Flask项目之手机端租房网站的实战开发(二)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...
- Flask项目之手机端租房网站的实战开发(十四)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...
- Flask项目之手机端租房网站的实战开发(六)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...
- Flask项目之手机端租房网站的实战开发(十一)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...
- Flask项目之手机端租房网站的实战开发(十)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...
- Flask项目之手机端租房网站的实战开发(八)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...
- Flask项目之手机端租房网站的实战开发(四)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...
随机推荐
- 微信公众号开发(二)获取AccessToken、jsapi_ticket
Access Token 在微信公众平台接口开发中,Access Token占据了一个很重要的地位,相当于进入各种接口的钥匙,拿到这个钥匙才有调用其他各种特殊接口的权限. access_token是公 ...
- 【Docker自定制镜像之Dockerfile】
镜像的定制,就是定制每一层所添加的配置.文件,如果可以把每一层修改.安装.构建.操作的命令都写入到一个脚本中,用脚本来构建.定制镜像,这个脚本就是Dockerfile Dockerfile是一个文本文 ...
- Idea下mybatis的错误—Module not specified
IDEA下使用maven的mybatis常见错误 错误类型一:导入项目引起的错误Module not specified 错误提示:idea Error Module not specified. 错 ...
- Swift学习笔记(14)--方法
1.分类 方法分为实例方法和类型方法 实例方法(Instance Methods):与java中的类似,略 类型方法(Type Methods):与java.oc中的类方法类似.声明类的类型方法,在方 ...
- Word中查找替换软回车键和回车键
在Word中使用搜索功能搜索“^p”组合字符串可以查找文档中的所有换行符(回车键),使用“^l”(英文输入状态下shift+6与小写字符L的组合)可以搜索所有的软回车符.使用替换功能就可以搜索替换二者 ...
- PatentTips - Virtual translation lookaside buffer
BACKGROUND OF THE INVENTION A conventional virtual-machine monitor (VM monitor) typically runs on a ...
- CODEVS——T1961 躲避大龙
http://codevs.cn/problem/1961/ 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 De ...
- 大型情感类电视连续剧--Android高德之旅(2)地图类型
总要说两句 今天继续我们的Android高德之旅,上一篇已经能够显示最主要的地图了.有主要的放大缩小功能.还有最后做的点击3D旋转.倾斜视角的效果.今天这篇文章来记录一下高德地图的5种地图类型. (其 ...
- 关于TabLayout+ViewPager组合实现多页面滑动
转载请注明出处:http://blog.csdn.net/ht_android/article/details/46647711 在android提供的design library中新增了一个控件,叫 ...
- win7中下mysql-5.6.22免安装配置
windows下mysql免安装配置 1. 下载mysql免安装压缩包 下载mysql-5.6.22-winx64.zip 解压到本地D:\mysql-5.6.22-winx64 2. 修改配置文件 ...