Flask项目之手机端租房网站的实战开发(十)
说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/86488529
目录
一丶区县信息前端编写
1.分析,当用户进入发布新房源,页面加载完毕即向后端发送请求拿取数据库中的区域信息数据,显示在页面上所在区县栏
2.所以需在此页面newhouse.js中进行如下编写
//当页面加载完成时,想后端获取区县信息
$.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>')
}
}else {
alert(resp.errmsg)
}
}, "json")
3.当通过js向后端获取区域信息全部对象,通过循环遍历获取每个对象,将每个对象中的aid以及aname通过append方式追加到id为area_id的select标签下,所以最后需要在newhouse.html中将原有的option标签删除
<select class="form-control" id="area-id" name="area_id">
<!--<option value="1">锦江区</option>-->
<!--<option value="2">青羊区</option>-->
<!--<option value="3">金牛区</option>-->
<!--<option value="4">武侯区</option>-->
<!--<option value="5">成华区</option>-->
<!--<option value="6">龙泉驿区</option>-->
<!--<option value="7">青白江区</option>-->
<!--<option value="8">新都区</option>-->
<!--<option value="9">温江区</option>-->
<!--<option value="10">郫都区</option>-->
<!--<option value="11">双流区</option>-->
<!--<option value="12">高新区</option>-->
<!--<option value="13">天府新区</option>-->
<!--<option value="14">新津县</option>-->
<!--<option value="15">大邑县</option>-->
<!--<option value="16">金堂县</option>-->
</select>
4.测试,重新启动程序,清除页面缓存,查看发布房源页面中的所有区县栏是否有数据,此时显示的区县数据,就是从后端数据库获取的
5.查看网页Network,从api/v1.0/area接口获取的数据
6.当前端页面需要从后端拿取很多数据时候,如果用上面的方式通过jquery想后端获取数据,再填充到标签中,这样就太麻烦了,所以这里需要在前端去引入一个js模板,来帮助我们更快的完成页面数据的填充
- step1 比如在房间信息详情页面,需要很多数据
- step2 使用art_template前端js模板来帮助我们解决此问题 https://aui.github.io/art-template/zh-cn/index.html
7.将发布新房源页面中的所在区县栏使用前端js模板进行改写
- step1 在newhouse.html中引入template.js
<script src="/static/js/template.js"></script>
- step2 在newhouse.html中定义模板
<script type="text/html" id="areas-template">
{{ each areas as area }}
<option value="{{area.aid}}">{{area.aname}}</option>
{{ /each }}
</script>
- step3 在newhouse.js中使用js模板
var html_text =template("areas-template", {areas:areas});
$("#area-id").html(html_text)
- step4 测试,清除缓存,刷新网页,查看结果使用js模板成功
二丶发布新房源后端接口编写
1.流程分析,在发布房源前端文件newhouse.html中将该页面下的上传图片栏隐藏了#form-house-image,当用户完成先关填写后,该上传房屋图片表单才会显示出来
- step1 在浏览器开发端进行显示
- step2 查看发布房源界面
2.在house.py中进行房屋信息接口编写
- step1 创建视图
@api.route("/houses/info", methods=["POST"])
@login_required
def save_house_info():
"""
保存房屋信息
:return:
"""
pass
- step2 获取数据
user_id = g.user_id
house_data = request.get_json()
- step3 从获取的data数据中拿取必填字段的值,facility配套设施可能啥都没有,前端就会传个空列表
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") # 最大入住天数
- step4 校验参数
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="参数不完整")
- step5 判断用户输入的房屋单价和押金是否为正确参数,通过存入数据库字段单位分,如果用户输入的值不能转换为float和int类型,说明参数错误
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="参数错误")
- step6 判断区县id是否存在
try:
area = Area.query.get(area_id)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="数据库异常")
- step7 如果在数据库中查询不到区域信息,表示区县信息有误
if area is None:
return jsonify(errno=RET.NODATA, errmsg="区县信息有误")
- step8 保存房屋信息到数据库
house = House(
user_id = user_id,
title = title,
price = price,
area_id = area_id,
address = address,
room_count = room_count,
acreage = acreage,
unit = unit,
capacity = capacity,
beds = beds,
deposit = deposit,
min_days = min_days,
max_days = max_days
)
- step9 获取设备设施数据id值
facility_ids = house_data.get("facility")
- step10 对获取设备设施字段的值进行判断,下判断这个值存不存在,当用户勾选设备设施时,举例facility_ids值为[2,4]
if facility_ids:
# 通过Facility类中的id值使用in_方法查询其中的id
# select * from ih_facility_info where id in facility_ids;
try:
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="数据库异常")
- step11 判断查询的每个facility对象是否存在,存在则保存设施数据
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="保存数据异常")
- step12 返回正确响应内容
return jsonify(errno=RET.OK, errmsg="OK", data={"house_id":house.id})
3.上传房屋图片接口编写
- step1 定义视图
@api.route("/houses/image", methods=["POST"])
@login_required
def save_house_image():
"""保存房屋图片"""
pass
- step2 获取图片
image_file = request.files.get("house_image")
- step3 获取图片id
house_id = request.form.get("house_id")
- step4 校验参数
if not all([image_file, house_id]):
return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
- step5 判断房屋是否在,存在才上传到七牛,如果不存在就不上传
try:
house = House.query.get(house_id)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="数据库异常")
- step6 house对象不存在则返回错误信息
if house is None:
return jsonify(errno=RET.NODATA, errmsg="房屋不存在")
- step7 获取图片二进制数据
image_data = image_file.read()
- step8 将图片保存到七牛中
try:
file_name = storage(image_data)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.THIRDERR, errmsg="上传图片失败")
- step9 保存图片信息到数据库中
house_image = HouseImage(house_id=house_id, url=file_name)
db.session.add(house_image)
- step10 当house对象中的index_image_url不存在时,设置网站主页房屋图片
if not house.index_image_url:
house.index_image_url = file_name
db.session.add(house)
- step11 提交到数据库
try:
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
return jsonify(errno=RET.DBERR, errmsg="保存图片异常")
- step12 拼接图片完整url,最后返回正确响应数据
image_url = constants.QINIU_URL_DOMAIN + file_name
return jsonify(errno=RET.OK, errmsg="OK", data={"image_url":image_url})
三丶发布新房源前端编写
1.在newhouse.js中进行提交房屋信息表单事件编写
$("#form-house-info").submit(function (e) {
})
- step1 阻止表单默认行为
e.preventDefault();
- step2 处理表单数据
var data = {};
$("#form-house-info").serializeArray().map(function (x) { data[x.name] = x.value });
- step3 收集用户勾选的设备id
var facility = [];
$(":checked[name=facility]").each(function (index, x) {facility[index] = $(x).val()});
- step4 将收集到的用户勾选id存到data数据库里的facility属性中
data.facility = facility;
- step5 通过ajax方式向后端接口发送请求
$.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)
}
}
},"json")
2.在newhouse.js中进行上传房屋图片表单事件编写
$("#form-house-image").submit(function (e) {
})
- step1 阻止表单默认行为
e.preventDefault();
- step2 利用jquery.form.min.js插件通过的ajaxSubmit对表单进行异步提交,当后端返回正确响应时, 往class 为 house-image-cons div标签下去添加img标签,该div下的img标签为用户上传图片的标签,上传一个图片则在此div下追加一个img标签
$(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"){
// 往class 为 house-image-cons div标签下去添加img标签
$(".house-image-cons").append('<img src="' + resp.data.image_url+'">')
}else {
alert(resp.errmsg);
}
}
})
四丶测试接口
1.运行项目,清除浏览器缓存,刷新网页,进入发布房源,博主这里使用的FS截图工具进行滚动窗口截图
2. 填写房屋信息
3.填写完数据后,点击发布房源信息,逻辑成功则显示上传房屋图片界面
查看数据库ih_house_info房屋信息表,数据显示为刚填写的表单勾选数据,此时并没有上传图片所以index_image_url为空
4.点击选择文件,选择桌面上的图片后,再点击上传,则显示在页面中
5.依次上传三张图片后
查看此时数据库ih_house_image表信息,在上图上传的三张图片是house_id为6的房屋例子,所以在下标显示house_id为6的图片url链接为三个
6.同时查看七牛云上的存储空间
五丶celery的使用
1.问题,我们在做网站后端程序开发时,会碰到这样的需求:用户需要在我们的网站填写注册信息,我们发给用户一封注册激活邮件到用户邮箱,如果由于各种原因,这封邮件发送所需时间较长,那么客户端将会等待很久,造成不好的用户体验.
2.解决,celery适用异步处理问题,当发送邮件、或者文件上传, 图像处理等等一些比较耗时的操作,我们可将其异步执行,这样用户不需要等待很久,提高用户体验。 celery的特点是:
- 简单,易于使用和维护,有丰富的文档。
- 高效,单个celery进程每分钟可以处理数百万个任务。
- 灵活,celery中几乎每个部分都可以自定义扩展。
3.Task Queue
celery通过消息进行通信,通常使用一个叫Broker(中间人)来协client(任务的发出者)和worker(任务的处理者). clients发出消息到队列中,broker将队列中的信息派发给worker来处理。
一个celery系统可以包含很多的worker和broker,可增强横向扩展性和高可用性能
4.在项目ihome目录下创建一个tasks包,用于处理项目中的需要的异步任务,在这个包下创建单一文件来处理对应的异步任务,这种方式是对于所有的web框架来说,都是万能的,像django中使用的djcelery包是别人针对于django框架封装好的包
- step1 在task包下创建一个task_sms.py文件,在这个文件中去编写对于发送短信的任务
- step2 定义celery对象
app = Celery("ihome", broker="redis://127.0.0.1:6379/1")
- step3 定义短信的异步任务
@app.task
def send_sms():
"""发送短信的异步任务"""
pass
- step4 导入之前定义好云通讯中封装的CCP类,并创建CCP的对象ccp
from ihome.libs.yuntongxun.SendSMS import CCP
- step5 通过ccp对象调用sendTemplateSMS方法,同时调用send_sms方法时传递三个参数,从这三个参数拿sendTemplateSMS方法中即可
@app.task
def send_sms(to, datas, tempId):
"""发送短信的异步任务"""
ccp = CCP()
ccp.sendTemplateSMS(to, datas, tempId)
- step6 回到api_1_0目录下的verify_code中,将之前写的get_sms_code方法中发送短信逻辑代码进行重新编写,跟之前写的逻辑不一样,之前是发送成功则返回发送成功msg,失败则返回发送失败msg,大多网站都是现在以下这种逻辑
# 使用celery异步发送短信
send_sms.delay(mobile, [sms_code, int(constants.SMS_CODE_REDIS_EXPIRES/60)], 1)
# 发送成功与否,用户自己去查看手机,大多网站都是这样做的
return jsonify(errno=RET.OK, errmsg="发送短信成功")
六丶测试celery
1.在终端中运行项目
2.另开一个终端执行celery -A ihome.tasks.task_sms worker -l info,-l代表开启日志 info级别,但是出现了报错
3.在百度上查询此报错信息,明白原来是celery4.0以上版本不支持windows
4.所以博主这里进行 pip install celery==3.1.7 进行3.x版本安装
5.在新开启的终端上,重新执行celery -A ihome.tasks.task_sms worker -l info,报错问题解决
6.进入网站注册界面http://127.0.0.1:5000/register.html,后进行注册,输入博主本人手机号,输入正确验证码,然后点击获取短信验证码后,回头查看celery终端,结果又报错了
7.这次报的错好像是跟redis有关,查看redis版本为3.0的
8.将redis版本缓存2.0的,再看看是否报错,pip install redis==2.10.5
9.先运行项目,再开启另一终端执行celery -A ihome.tasks.task_sms worker -l info
- step1 在注册页面进行注册
- step2 查看celery终端日志,显示七牛SDK发送短信成功日志
- step3 查看博主手机上短信验证码为987427
- step4 查看redis数据库1中的keys
七丶celery以目录形式创建
1.在ihome/tasks目录下创建main.py用于启动文件,再创建一个config.py用于作配置文件,然后在tasks目录下创建一个sms包,再该包下创建一个tasks.py文件或者是celery.py文件用于创建worker
2.拆分task_sms.py文件
- step1 在启动文件main.py中编写以下代码
app = Celery("ihome", broker="redis://127.0.0.1:6379/1")
- step2 将如下代码拷贝到tasks.py中
@app.task
def send_sms(to, datas, tempId):
"""发送短信的异步任务"""
ccp = CCP()
ccp.sendTemplateSMS(to, datas, tempId)
- step3 将main.py中创建app对象中的配置文件拿到config.py中
BROKER_URL = "redis://127.0.0.1:6379/1"
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/2'
- step4 回到main.py中进入如下编写
app = Celery("ihome")
# 引入配置信息
app.config_from_object(config)
# 自动搜索任务
app.autodiscover_tasks(["ihome.tasks.sms"])
- step5 回到ihome/api_1_0/verify_code.py中,将之前写的代码进行修改,将不在从from ihome.tasks.task_sms去导入send_sms,而是从我们刚定义好的sms.tasks中去导入send_sms
from ihome.tasks.sms.tasks import send_sms
3.测试
- step1 首先启动项目,再另起终端启动worker,结果又特么报错了
- step2 这个错是因为操作系统原因导致的,在linux系统上运行则不会保错
原因:因为windows操作系统的原因,在Windows中,多进程multiprocessing使用的是序列化pickle来在多进程之间转移数据,而socket对象是不能被序列化的,但是在linux操作系统上却没问题,因为在linux上多进程multiprocessing使用的是fork,所以在windows上可以改用多线程,而celery是使用多进程以及携程方式进行异步工作,博主又是在windows环境进行测试开发,所以这里先暂时这样,等开发完成部署在linux服务器即可
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 ...
随机推荐
- Windows10上使用windbg调试Chromium Windows。
###目的###Windows10上使用windbg调试Chromium Windows. 安装Windows 10 SDK时, 就包含了windbg.exe."C:\Program Fil ...
- React-router 4 总结
React-Router 4: BrowserRouter包裹整个应用 Router路由对应渲染的组件,可嵌套 Link跳转专用 首先 然后 其他组件: url参数 Route组建参数可用冒号标识参数 ...
- 重装python 和 yum
https://blog.csdn.net/ghostyusheng/article/details/https://segmentfault.com/q/1010000009194060/a-102 ...
- 今日SGU 5.15
最近事情好多,数据库作业,没天要学2个小时java,所以更新的sgu就比较少了 SGU 131 题意:给你两种小块一种,1*1,一种2*2-1*1,问你填满一个m*n的矩形有多少钟方法,n和m小于等于 ...
- 【Henu ACM Round#17 D】Hexagons!
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 题目的图吓人. 找下规律就会发现从内到外是1,6,12,18 即1,16,26,36... 即1+6(1+2+3+...) 等差求和 ...
- CCF模拟题 最大的矩形
最大的矩形 时间限制: 1.0s 内存限制: 256.0MB 问题描述 在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi.这n个矩形构成了一个直方 ...
- php, hhvm与odp & Unix domain Socket方式
接上一篇,复习一下 启动php或hhvm: php/sbin/php-fpm start hhvm/bin/hhvm_control start 启动nginx或lighttpd: webserver ...
- C#加减乘除
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Jmeter作为工具的性能测
[原创]相对完整的一套以Jmeter作为工具的性能测试教程(接口性能测试,数据库性能测试以及服务器端性能监测) 准备工作 jmeter3.1,为什么是3.1,因为它是要配合使用的serveragent ...
- 我的第一个Django项目
1.创建Django项目 命令:django-admin startproject 项目名 注意:创建应用必须先进入虚拟环境. 项目目录如下: 目录层级说明: __init__.py: 说明demo0 ...