基本信息展示

1. 后端接⼝设计

接⼝描述 接⼝参数
请求⻚⾯ 详情⻚
请求⽅式 GET
请求地址 /house/int:hid
返回数据 房源对象,包括:id、address、rooms、area、price、liulanliang等信息
房源数据所需字段如下:
参数 类型 说明
id int 房源id
title str 标题
rooms str 户型
area str ⾯积
price str 价格
addr str 房源地址
traffic str 交通情况
region str 地区
direction str 朝向
type str 浏览量
time int 发布时间,格式是时间戳
liangdian str 房屋亮点
sheshi str 房屋⾃带的电器、家具等设施
tel str 房东电话

2. 后端逻辑

# 实现房源的基本信息展示
"""
1. 创建⼀个视图函数 动态路由 /house/<int:hid> method=get
2. 使⽤房源编号 通过sqlalchemy获取编号对应的房源对象 就可以获取对象中的信息了
3. 使⽤render_template进⾏模板的渲染
"""
@detail_page.route('/house/<int:hid>')
def detail(hid):
# 使⽤房源编号 通过sqlalchemy获取编号对应的房源对象
house = House.query.get(hid)
# 处理配套设施的数据,变换成列表
sheshi_str = house.sheshi # 床-宽带-洗⾐机-空调-热⽔器-暖⽓
sheshi_list = sheshi_str.split('-')
return render_template('detail_page.html', house=house, sheshi=sheshi_list)

配套设施
之前我们存放在数据库中的配套设施信息是这样的
空调-热⽔器-暖⽓-可做饭-卫⽣间
所以我们在使⽤的时候,需要对其进⾏处理,转换成 [‘空调’, ‘热⽔器’,‘暖⽓’,‘可做饭’,‘卫⽣间’]

3. 前端逻辑

<!--大标题--><div class="col-lg-12 col-md-12 detail-header"><h3>{{ house.address }}&nbsp{{ house.rooms }}</h3><div class="describe"><span>为您精准定位,当前城市房源信息</span></div></div><!--左详情--><div class="col-lg-8 col-md-8"><div class="course"><!--图--><div><a href="#"><img class='img-fluid img-box' src="/static/img/house-bg1.jpg" alt=""></a></div><!--价格--><div class="house-info"><span class="price">¥&nbsp{{ house.price }}/月</span><span class="collection" id="btn-collection"><a><i class="fa fa-heart"aria-hidden="true"> 收藏</i></a></span></div><!--基本信息标题--><div class="attribute-header"><h4>基本信息</h4></div><!--属性1--><div class="row attribute-info"><div class="col-lg-2 col-md-2"><span class="attribute-text">基本属性</span></div><div class="col-lg-4 col-md-4"><div><span class="attribute-text">房屋户型:</span><span class="info-text">{{ house.rooms }}</span></div><div><span class="attribute-text">建筑面积:</span><span class="info-text">{{ house.area }}平米</span></div><div><span class="attribute-text">房屋朝向:</span><span class="info-text">{{ house.direction }}</span></div></div><div class="col-lg-6 col-md-6"><div><span class="attribute-text">所在区域:</span><span class="info-text">{{ house.address }}</span></div><div><span class="attribute-text">租住类型:</span><span class="info-text">{{ house.rent_type }}</span></div><div><span class="attribute-text">房东电话:</span><span class="info-text">{{ house.phone_num }}</span></div></div></div><!--属性2--><div class="row attribute-info"><div class="col-lg-2 col-md-2"><span class="attribute-text">房屋卖点</span></div><div class="col-lg-8 col-md-8"><div><span class="attribute-text">交通条件:</span><span class="info-text">{{ house.traffic | dealNone }}</span></div><div><span class="attribute-text">优势条件:</span><span class="info-text">{{ house.title }}</span></div></div></div><!--房源配套设施--><div class="attribute-header"><h4>房源配套设施</h4></div><!--设施列表--><div class="row attribute-info"><div class="col-lg-2 col-md-2"><span class="icon-1"></span>{% if '冰箱' in sheshi %}<span class="attribute-text-sm" style="color: #f1c40f">冰箱</span>{% else %}<span class="attribute-text-sm"><s>冰箱</s></span>{% endif %}</div><div class="col-lg-2 col-md-2"><span class="icon-2"></span>{% if '洗衣机' in sheshi %}<span class="attribute-text-sm" style="color: #f1c40f">洗衣机</span>{% else %}<span class="attribute-text-sm"><s>洗衣机</s></span>{% endif %}</div><div class="col-lg-2 col-md-2"><span class="icon-3"></span>{% if '电视' in sheshi %}<span class="attribute-text-sm" style="color: #f1c40f">电视</span>{% else %}<span class="attribute-text-sm"><s>电视</s></span>{% endif %}</div><div class="col-lg-2 col-md-2"><span class="icon-4"></span>{% if '空调' in sheshi %}<span class="attribute-text-sm" style="color: #f1c40f">空调</span>{% else %}<span class="attribute-text-sm"><s>空调</s></span>{% endif %}</div><div class="col-lg-2 col-md-2"><span class="icon-5"></span>{% if '暖气' in sheshi %}<span class="attribute-text-sm" style="color: #f1c40f">暖气</span>{% else %}<span class="attribute-text-sm"><s>暖气</s></span>{% endif %}</div></div><div class="row attribute-info"><div class="col-lg-2 col-md-2"><span class="icon-6"></span>{% if '热水器' in sheshi %}<span class="attribute-text-sm" style="color: #f1c40f">热水器</span>{% else %}<span class="attribute-text-sm"><s>热水器</s></span>{% endif %}</div><div class="col-lg-2 col-md-2"><span class="icon-7"></span>{% if '天然气' in sheshi %}<span class="attribute-text-sm" style="color: #f1c40f">天然气</span>{% else %}<span class="attribute-text-sm"><s>天然气</s></span>{% endif %}</div><div class="col-lg-2 col-md-2"><span class="icon-8"></span>{% if '床' in sheshi %}<span class="attribute-text-sm" style="color: #f1c40f">床</span>{% else %}<span class="attribute-text-sm"><s>床</s></span>{% endif %}</div><div class="col-lg-2 col-md-2"><span class="icon-9"></span>{% if '宽带' in sheshi %}<span class="attribute-text-sm" style="color: #f1c40f">WIFI</span>{% else %}<span class="attribute-text-sm"><s>WIFI</s></span>{% endif %}</div><div class="col-lg-2 col-md-2"><span class="icon-10"></span>{% if '电梯' in sheshi %}<span class="attribute-text-sm" style="color: #f1c40f">电梯</span>{% else %}<span class="attribute-text-sm"><s>电梯</s></span>{% endif %}</div></div></div></div>

户型占⽐

1. 后端接⼝设计

接⼝描述 接⼝参数
请求⻚⾯ 详情⻚
请求⽅式 GET
请求地址 /get/piedata/
返回数据 json数据格式

{'data': [{'name':'2室1厅', 'value':86}, {'name':'3室1厅', 'value':69}]}

每⼀组的房源数据所需字段如下:
参数 类型 说明
name str 户型
value int 数量

2. 效果及功能介绍


功能的作⽤:
统计房源所属街道的户型占⽐
功能的⽤途:
提供房源附近的户型占⽐信息,⽅便⽤户了解哪种户型更加好找
关于所属街道的解释:
房源的address:顺义-顺义城-怡馨家园
那么房源所属街道:顺义-顺义城,对应房源的block字段

3. 户型占⽐功能实现逻辑

4.1 第⼀步和第⼆步 前端发送请求

// 获取pie
$.ajax({url: "/get/piedata/{{ house.block }}",
type: 'get',
dataType: 'json',
success: function (data) {pie_chart(data['data'])
}
});

4.2 第三步 数据选择、处理、变换和返回

# 实现户型占比功能
"""
1. 创建一个视图函数 /get/piedata/<block> get请求方式
2. 获取block字段 使用sqlalchemy来查询符合block字段的房源
3. 分组统计房源中的户型 和 数量  根据数量对 户型进行排序 降序排序
4. 封装数据
5. 提交给echarts
"""
@detail_page.route('/get/piedata/<block>')
def return_pie_data(block):print(block)# 1. 选择 filter(House.block == block)# 2. 预处理 group_by(House.rooms).order_by(func.count().desc())# 3. 预处理的结果是 resultresult = House.query.with_entities(House.rooms, func.count()).filter(House.block == block).group_by(House.rooms).order_by(func.count().desc()).all()# 4. 对数据进行变换 result ==> {'name': one_house[0], 'value': one_house[1]}data = []for one_house in result:data.append({'name': one_house[0], 'value': one_house[1]})return jsonify({'data': data})

4.3. 渲染-数据展示

function pie_chart(data) {var myChart = echarts.init(document.getElementById('pie'));window.addEventListener('resize', function () {myChart.resize();});var option = {tooltip : {trigger: 'item',formatter: "{a} <br/>{b} : {c} ({d}%)",},series:[{name: '户型的占比',type: 'pie',radius: ['0%', '50%'],center: ['50%', '50%'],labelLine: {normal: {show: true},// 选中后加重表现emphasis: {show: true}},// 饼状图的内部名字label: {normal: {show: true},emphasis: {show: true}},//itemStyle: {emphasis: {shadowBlur: 10,shadowOffsetX: 0,shadowColor: 'rgba(0, 0, 0, 0.5)'}},data: data,}]};myChart.setOption(option);
}

⼩区房源数量TOP20

1. 后端接⼝设计

接⼝描述 接⼝参数
请求⻚⾯ 详情⻚-当前街道的⼩区数量top20
请求⽅式 GET
请求地址 /get/columndata/
返回数据 json数据格式
图表类型 柱状图

{'name_list_x': ['紫⾦⻓安', '橡树湾', '友谊嘉园', '⻄钓⻥台嘉园', '华清嘉园', '永旺家园',
'碧⽔云天', '⼤⽜坊回迁房', '远⼤园五区', '常⻘园北⾥', '缘溪堂', '颐源居', '五福玲珑居', '万
泉新新家园', '京泉馨苑', '世纪城晨⽉园', '颐慧佳园', '肖家河新村东区', '柳浪家园', '上地东⾥',
'曙光花园望⼭园', '和泓四季'], 'num_list_y': [123, 95, 86, 85, 81, 77, 73, 73, 67, 63,
62, 60, 58, 56, 55, 54, 52, 49, 48, 48, 46, 44]}

参数 类型 说明
name_list_x 列表 X轴的变量,⼩区名称
num_list_y 列表 Y轴的变量,⼩区数量

2. 效果及功能介绍


功能的作⽤:
先获取房源所处街道附近的所有⼩区,然后统计各个⼩区的在租房源数量
功能的⽤途:
提供房源附近各个⼩区在租房源数量,⽅便⽤户寻找⽬标房源

4.1 第⼀步 前端发送请求

// 获取column$.ajax({url: "/get/columndata/{{ house.block }}",type: 'get',dataType: 'json',success: function (data) {column_chart(data['data'])}});

4.2 第⼆步 数据选择、处理变换和返回数据

# 实现本地区小区数量TOP20功能
"""
1. 创建一个视图函数 /get/columndata/<block> get请求方式
2. 获取block字段 使用sqlalchemy获取符合这个block字段的所有房源数据 --- 目标数据
3. 预处理 对目标数据 进行分组 依据小区名字进行分组 统计每个小区的房源数量  就可以根据房源数量 对小区进项排序 降序排序的方式————预处理的结果
4. 进行数据的变换 变换成能够提交给echarts的数据格式
5. 使用jsonify返回数据给前端
"""
@detail_page.route('/get/columndata/<block>')
def return_bar_data(block):result = House.query.with_entities(House.address, func.count()).filter(House.block == block).group_by(House.address).order_by(func.count().desc()).all()  # 小区名字出现在address这个字段中# {'name_list_x':['xxx小区','xxx小区','xxx小区'],'num_list_y':[160,149,128]}name_list = []num_list = []for addr, num in result:# 顺义-顺义城-西辛南区 ==> ['顺义-顺义城', '西辛南区'] ==> 西辛南区xiaoqu_name = addr.rsplit('-', 1)[1]name_list.append(xiaoqu_name)![在这里插入图片描述](https://img-blog.csdnimg.cn/b9d7e97b29fd4e50a0b614a115c4f427.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAcGVhY2V6aGk=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)num_list.append(num)# 获取TOP20的数据 大于20的就直接舍去if len(name_list) > 20:data = {'name_list_x': name_list[:20], 'num_list_y': num_list[:20]}else:data = {'name_list_x': name_list, 'num_list_y': num_list}return jsonify({'data': data})

4.3 渲染-数据展示

function column_chart(data) {var salaru_line = echarts.init(document.getElementById('scolumn_line'));window.addEventListener('resize', function () {salaru_line.resize();});// var XData=['东方凤雅台', '仙桐御景', '仙湖山庄二期', '仙湖枫景家园', '兰亭国际公寓', '华景园御庭轩', '合正锦园一期', '名骏豪庭', '广岭家园', '新世界四季御园', '新世界鹿茵翠地', '桐景花园', '聚宝华府', '金色年华家园', '鸿景翠峰', '鹏兴花园一期', '鹏兴花园三期', '鹏兴花园二期', '鹏兴花园六期', '鹏莲花园'];// var yData=[1, 1, 1, 3, 1, 1, 1, 3, 4, 1, 1, 1, 2, 2, 1, 2, 1, 8, 1, 1];// {'name_list_x': name_list, 'num_list_y': num_list}var XData = data['name_list_x'];var yData = data['num_list_y'];var dataMin = parseInt(Math.min.apply(null, yData)/2);var option = {backgroundColor: "#fff",grid: {height:'200px'},xAxis: {axisTick: {show: false},splitLine: {show: false},splitArea: {show: false},data: XData,axisLabel: {formatter: function (value) {var ret = ""; //拼接加\n返回的类目项var maxLength = 1; //每项显示文字个数var valLength = value.length; //X轴类目项的文字个数var rowN = Math.ceil(valLength / maxLength); //类目项需要换行的行数if (rowN > 1) //如果类目项的文字大于3,{for (var i = 0; i < rowN; i++) {var temp = ""; //每次截取的字符串var start = i * maxLength; //开始截取的位置var end = start + maxLength; //结束截取的位置//这里也可以加一个是否是最后一行的判断,但是不加也没有影响,那就不加吧temp = value.substring(start, end) + "\n";ret += temp; //凭借最终的字符串}return ret;} else {return value;}},interval: 0,fontSize: 11,fontWeight: 100,textStyle: {color: '#555',}},axisLine: {lineStyle: {color: '#4d4d4d'}}},yAxis: {axisTick: {show: false},splitLine: {show: false},splitArea: {show: false},min: dataMin,axisLabel: {textStyle: {color: '#9faeb5',fontSize: 16,}},axisLine: {lineStyle: {color: '#4d4d4d'}}},"tooltip": {"trigger": "item","textStyle": {"fontSize": 12},"formatter": "{b0}: {c0}套"},series: [{type: "bar",itemStyle: {normal: {color: {type: 'linear',x: 0,y: 0,x2: 0,y2: 1,colorStops: [{offset: 0,color: '#00d386' // 0% 处的颜色}, {offset: 1,color: '#0076fc' // 100% 处的颜色}],globalCoord: false // 缺省为 false},barBorderRadius: 15,}},// barWidth: 7,data: yData}]};salaru_line.setOption(option, true);
}

户型价格⾛势

1. 后端接⼝设计

接⼝描述 接⼝参数
请求⻚⾯ 详情⻚
请求⽅式 GET
请求地址 /get/brokenlinedata/
返回数据 json数据格式
图表类型 折线图

{'data': {'2室1厅': [50.6, 45.32], '1室1厅': [48.36, 51.08], '2室2厅': [48.34, 59.42]
, '3室2厅': [48.28, 48.14]}}

2. 效果及功能介绍

功能的作⽤:
先获取房源所处街道附近的所有房源价格,然后获取最近半个⽉四个户型的平均价格(租⾦/⾯积)
功能的⽤途:
提供房源街道区域的户型价格⾛势,⽅便⽤户了解市场⾏情

4.1 第⼀步 前端发送请求

// 获取broken_line
$.ajax({url: "/get/brokenlinedata/{{ house.block }}",type: 'get',dataType: 'json',success: function (data) {broken_line_chart(data['data'])}
});

4.2 第⼆步 数据选择、处理变换和返回数据

# 实现户型价格走势
"""
1. 创建一个视图函数 /get/brokenlinedata/<block> get请求方式
2. 获取block字段 使用sqlalchemy获取符合block字段 和 户型的房源数据 --- 目标数据
3. 预处理 对目标数据 进行分组 分组的依据是房源的发布时间 使用func函数中avg()获取 price/area价格 按照发布时间来进行排序 默认方式进行排序  --- 预处理的结果
4. 对预处理的结果 进行变换 的到 提供给echarts的数据  {'data':{'1室1厅':[76.49, 42.86]}}
"""
@detail_page.route('/get/brokenlinedata/<block>')
def return_brokenline_data(block):# 1室1厅的户型result = House.query.with_entities(func.avg(House.price / House.area)).filter(House.block == block,House.rooms == '1室1厅').group_by(House.publish_time).order_by(House.publish_time).all()data = []for i in result[-14:]:data.append(round(i[0], 2))# 2室1厅的户型result1 = House.query.with_entities(func.avg(House.price / House.area)).filter(House.block == block,House.rooms == '2室1厅').group_by(House.publish_time).order_by(House.publish_time).all()data1 = []for i in result1[-14:]:data1.append(round(i[0], 2))# 2室2厅的户型result2 = House.query.with_entities(func.avg(House.price / House.area)).filter(House.block == block,House.rooms == '2室2厅').group_by(House.publish_time).order_by(House.publish_time).all()data2 = []for i in result2[-14:]:data2.append(round(i[0], 2))# 3室2厅的户型result3 = House.query.with_entities(func.avg(House.price / House.area)).filter(House.block == block,House.rooms == '3室2厅').group_by(House.publish_time).order_by(House.publish_time).all()data3 = []for i in result3[-14:]:data3.append(round(i[0], 2))return jsonify({'data': {'1室1厅': data, '2室1厅': data1, '2室2厅': data2, '3室2厅': data3}})

4.3 第三步 渲染-数据展示

function broken_line_chart(data) {var salaru_line = echarts.init(document.getElementById('broken_line'), 'infographic');window.addEventListener('resize', function () {salaru_line.resize();});// data ==> {'3室2厅': [26, 28, 42, 26, 22, 28, 22, 26, 32, 17, 22], '2室1厅': [25, 28, 27, 40, 33, 29, 28, 37, 30, 28, 32], '2室2厅': [37, 37, 36, 47, 34, 32, 32, 37, 36, 29, 31], '1室1厅': [35, 47, 44, 47, 44, 44, 31, 32, 34, 34, 34]}var Data1 = data['3室2厅'];var Data2 = data['2室2厅'];var Data3 = data['2室1厅'];var Data4 = data['1室1厅'];var date_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];var option = {tooltip: {trigger: 'axis',},grid: {containLabel: true,left: '3%',right: '4%',bottom: '3%',},xAxis: {type: 'category',boundaryGap: false,data: date_list},yAxis: {type: 'value'},series: [{name:'3室2厅',type:'line',data:Data1},{name:'2室2厅',type:'line',data:Data2},{name:'2室1厅',type:'line',data:Data3},{name:'1室1厅',type:'line',data:Data4}]
};salaru_line.setOption(option, true);
}

预测房价

1. 后端接⼝设计

接⼝描述 接⼝参数
请求⻚⾯ 详情⻚-所在区域内房价预测
请求⽅式 GET
请求地址 /get/scatterdata/
返回数据 json数据格式
图表类型 散点图

{'data': [[0, 85], [1, 110], [2, 105], [3, 87], [4, 84], [5, 86], [6, 74], [7, 67],
[8, 91], [9, 76], [10, 63], [11, 68], [12, 80], [13, 93], [14, 115], [15, 72], [16
, 81], [17, 88], [18, 121], [19, 91], [20, 78], [21, 91], [22, 155], [23, 180], [24
, 84], [25, 199], [26, 98], [27, 104], [28, 108], [29, 125], [30, 91], [31, 76], [32
, 78], [33, 74], [34, 102], [35, 112], [36, 88], [37, 67], [38, 124], [39, 90], [40
, 112], [41, 90], [42, 106]]}

参数 类型 说明
data 数组列表 数组[X,Y]。X为时间,Y为单价。

2. 效果展示


功能的作⽤:
先获取房源所处街道附近的所有房源价格,然后根据时间统计每⽇的平均价格(租⾦/⾯积)
功能的⽤途:
提供房源街道区域的价格⾛势,⽅便⽤户了解市场⾏情

4.1 第⼀步 前端发送请求

// 获取scatter$.ajax({url: "/get/scatterdata/{{ house.block }}",type: 'get',dataType: 'json',success: function (data) {getdata1(data['data']);}});

3.2 第⼆步 数据选择、处理、变换和返回数据

# 实现房价预测功能
"""
1. 创建一个视图函数 /get/scaterdata/<block> get请求方式
2. 获取block字段 然后使用sqlalchemy获取符合blocl字段的所有房源 --- 目标数据
3. 预处理 对目标数据进行分组 分组的依据就是房源的发布时间 使用func中avg()获取 price/area价格 按照发布时间进行排序  --- 预处理的结果
4. 对预处理的结果进行变换 得到能够提交给echarts的数据格式  {'data':[[0,50],[1,16.87],[2,76.49]]}
"""
@detail_page.route('/get/scatterdata/<block>')
def return_scatter_data(block):# 1. 实现已有数据的渲染result = House.query.with_entities(func.avg(House.price / House.area)).filter(House.block == block).group_by(House.publish_time).order_by(House.publish_time).all()data = []X = []Y = []for index, i in enumerate(result):X.append([index])Y.append(round(i[0], 2))data.append([index, round(i[0], 2)])  # round函数 可以完成浮点数的四舍五入的运算 传入两个参数 第一参数:浮点数 第二参数:保留的小数位# 2. 对未来一天(第二天)的价格进行预测predict_value = len(data)predict_outcome = linear_model_main(X, Y, predict_value)print(predict_outcome)p_outcome = round(predict_outcome[0], 2)# 3. 将预测的数据添加入data中data.append([predict_value, p_outcome])return jsonify({'data': data})

4. 渲染-数据展示

function getdata1(data) {var center1 = echarts.init(document.getElementById('f_line'), 'infographic');window.addEventListener('resize', function () {center1.resize();});var myRegression = ecStat.regression('linear', data);myRegression.points.sort(function (a, b) {return a[0] - b[0];});option = {title: {subtext: '根据最近的房价,预测价格走势',left: 'center',},tooltip: {trigger: 'axis',axisPointer: {type: 'cross'}},grid: {show: true,//是否显示直角坐标系的网格,true显示,false不显示left: '13%',//grid组件离容器左侧的距离containLabel: false,//grid 区域是否包含坐标轴的刻度标签,在无法确定坐标轴标签的宽度,容器有比较小无法预留较多空间的时候,可以设为 true 防止标签溢出容器。},xAxis: {type: 'value',height: '100px',splitLine: {lineStyle: {type: 'dashed'}},},yAxis: {type: 'value',min: 1.5,splitLine: {lineStyle: {type: 'dashed'}},},series: [{name: '分散值(实际值)',type: 'scatter',label: {emphasis: {show: true,position: 'left',textStyle: {color: 'blue',fontSize: 12}}},data: data}, {name: '线性值(预测值)',type: 'line',showSymbol: false,data: myRegression.points,markPoint: {itemStyle: {normal: {color: 'transparent'}},label: {normal: {show: true,position: 'left',formatter: myRegression.expression,textStyle: {color: '#333',fontSize: 12}}},data: [{coord: myRegression.points[myRegression.points.length - 1]}]}}]};center1.setOption(option, true);}

协同过滤算法

1. 协同过滤算法

通过寻找与⾃⼰兴趣、⾏为相似的对象 使⽤他们以往的数据 ,来给⾃⼰推荐⾃⼰想要的东⻄。

2. 协同过滤算法的分类

2.1 基于物品的协同算法

2.2 基于⽤户的协同算法

3. 本项⽬使⽤基于⽤户的协同过滤算法

4. 使⽤⽪尔逊相关系数做推荐

4.2 实现pearson推荐算法

from utils.con_to_db import query_data
from math import sqrt# 获取推荐表中所有的用户id
"""
1. 创建一个函数
2. 获取推荐表中的所有用户浏览的信息, 根据用户id进行分类 ,获取所有的用户的id
3. 对获取到的结果进行变形
"""
def get_total_u_id():# 用来获取推荐表中 所有的用户idsql = 'select user_id from tuijian group by user_id'result = query_data(sql)# print(result)# 将所有的用户id放入到一个列表中total_u_id = list([i[0] for i in result])# print(total_u_id)return total_u_id# 获取每个用户的历史记录的需求
"""
1. 创建一个函数
2. 通过user_id这个字段 来过滤出当前用户的所有的浏览历史 从当前的这组数据中 获取house_id  和 score
3. 对获取到的数据 进行组装  {1: {123:4, 234:2} }  ==> {u_id: {house_id: score, house_id:score.....}}
"""
def get_user_info(user_id):# 使用sql语句完成数据库的查询sql = 'select user_id, house_id, score from tuijian where user_id = "{}"'.format(user_id)result = query_data(sql)# print(result)data = {}for info in result:# data字典中 还没有插入过当前用户的信息的操作if info[0] not in data.keys():data[info[0]] = {info[1]: info[2]}else:data[info[0]][info[1]] = info[2]# print(data)return data# 获取两个用户的相似度
"""
1. 创建一个函数
2. 获取两个用户的 各自的浏览记录
3. 后去两个用户共同的浏览过的房源
4. 使用pearson公式 来获取他们的相似度
"""def pearson_sim(user1, sim_user):# 获取两个用户的 各自的浏览记录user1_data = get_user_info(user1)[int(user1)]user2_data = get_user_info(sim_user)[int(sim_user)]# 两个用户共同的浏览过的房源common = []for key in user1_data.keys():  # keys函数使用来获取字典中 所有的键 返回的是盛放键的列表if key in user2_data.keys():common.append(key)# 如果没有共同评论过的房源 就返回0if len(common) == 0:return 0# 统计相同房源的个数n = len(common)# print(n, common)# 计算评分和  Ex和Eyuser1_sum = sum([user1_data[hid] for hid in common])user2_sum = sum([user2_data[hid] for hid in common])# 计算评分的平方和 E(x)^2 E(y)^2pow_sum1 = sum([pow(user1_data[hid], 2) for hid in common])pow_sum2 = sum([pow(user2_data[hid], 2) for hid in common])# 计算乘积的和PSum = sum([float(user1_data[hid] * float(user2_data[hid])) for hid in common])# 组装成分子fenzi = PSum - (user1_sum * user2_sum / n)# 组装分母fenmu = sqrt(pow_sum1 - pow(user1_sum, 2) / n) * (pow_sum2 - pow(user2_sum, 2) / n)if fenmu == 0:return 0result = fenzi / fenmu# print(result)return result# 获取相似度在前十名的用户
"""
1. 创建一个函数
2. 获取推荐表中的全部的用户的id
3. 遍历全部用户的id 获取除自己之外的所有用户的 相似度
4. 使用sort函数来进行降序排序 获取前十名的用户id
"""def top10_similar(UserID):#  获取推荐表中的全部的用户的idtotal_u_id = get_total_u_id()# 遍历全部用户的id 获取除自己之外的所有用户的 相似度res = []for u_id in total_u_id:if int(UserID) != u_id:similar = pearson_sim(int(UserID), int(u_id))if similar > 0:res.append((u_id, similar))# print(res)# 使用sort函数来进行降序排序 获取前十名的用户idres.sort(key=lambda val: val[1], reverse=True)# sort函数可以对列表进行排序 默认使用升序方式排序 使用reverse改为降序排序# print(res[:10])return res# 获取推荐的房源
"""
1. 创建一个函数
2. 获取相似度最高的用户 通过这个用户 获取他完整的 浏览记录
3. 获取当前这个用户的 完整浏览记录
4. 判断 当前用户中没有  但是在 相似用户中 评价最高的房源
5. 按照 评分 使用sort来进行排序 降序排序 获取前6个
"""def recommed(user):# 判断获取到的top10_similar()函数的结果 是否有值,如果没有值 返回Noneif len(top10_similar(user)) == 0:return None# 获取相似度最高的用户idtop_sim_user = top10_similar(user)[0][0]# 获取相似度最高的用户 的完整浏览记录items = get_user_info(top_sim_user)[int(top_sim_user)]  # {1: {123:4, 234:2}}# 获取当前用户自己的浏览记录user_data = get_user_info(user)[int(user)]# 筛选当前用户 未浏览的房源 并添加到列表中recommendata = []for item in items.keys():if item not in user_data.keys():recommendata.append((item, items[item]))# print(recommendata)recommendata.sort(key=lambda val: val[1], reverse=True)# print(recommendata)# 返回评分最高的6套房源if len(recommendata) > 6:return recommendata[:6]else:return recommendataif __name__ == '__main__':# get_total_u_id()# get_user_info(1)# pearson_sim(1, 23)# top10_similar(3)recommendata=  recommed(1)print(recommendata)

智能推荐

1. 后端逻辑

智能推荐的逻辑应该在详情⻚detail视图函数的中实现。⽽在实现的时候,我们需要分登陆状态和⾮登录状态两种情况来进⾏讨论,详细的逻辑如下图所示:

# 实现房源的基本信息展示
"""
1. 创建一个视图函数 动态路由 /house/<int:hid> method=get
2. 使用房源编号 通过sqlalchemy获取编号对应的房源对象 就可以获取对象中的信息了
3. 使用render_template进行模板的渲染
"""
@detail_page.route('/house/<int:hid>')
def detail(hid):house = House.query.get(hid)sheshi_str = house.sheshi  # 床-宽带-洗衣机-空调-热水器-暖气sheshi_list = sheshi_str.split('-')# 判断用户是否处于登录状态下name = request.cookies.get('name')# 定义一个用来盛放推荐房源的列表容器tuijian = []# 在登陆状态下if name:# 获取用户对象user = User.query.filter(User.name == name).first()# 获取用户对象的浏览记录seen_id_str = user.seen_id  # 浏览记录的格式:'123,234,345' 或着 null# 已经存在的浏览记录if seen_id_str:# 对浏览记录进行变形 将字符串 转换成 列表 '123,234,345' ==> ['123','234','345']seen_id_list = seen_id_str.split(',')# 将列表转换成 元素为整数的列表 ['123','234','345'] ==> [123, 234, 345]# 借助set函数 来去重set_id = set([int(i) for i in seen_id_list]) # [123, 234, 345] ==> {123, 234,345}# 如果hid在浏览记录中if hid in set_id:pass# 如果hid不在浏览记录中else:new_seen_id_str = seen_id_str + ',' + str(hid)user.seen_id = new_seen_id_strdb.session.commit()# 浏览记录为nullelse:# 直接将当前的hid插入到浏览记录中user.seen_id = str(hid)db.session.commit()# TODO 实现推荐功能# 添加用户的浏览次数# 查询 tuijian表中是否有当前用户 对此房源的浏览记录info = Tuijian.query.filter(Tuijian.user_id==user.id, Tuijian.house_id==house.id).first()# 第一种情况,该用户对此房源已经浏览过了,就对推荐表中score进行加一if info:print('推荐表中已经存在<user:{}>对<house:{}>的浏览记录'.format(user.id, house.id))new_score = info.score + 1info.score = new_scoredb.session.commit()print('完成:对<user:{}><house:{}>浏览记录+1的操作'.format(user.id, house.id))# 第二种情况,该用户对此房源没有浏览过,直接插入一条新的数据else:new_info = Tuijian(user_id=user.id, house_id=house.id, title=house.title, address=house.address, block=house.block, score=1)db.session.add(new_info)db.session.commit()print('推荐表中不存在<user:{}>对<house:{}>的浏览记录,因此添加一条新的信息到推荐表中'.format(user.id, house.id))# 根据推荐系统的返回值,给用户返回推荐结果# 调用推荐系统的recommed函数result = recommed(user.id)# 第一种情况,有推荐的返回值,就代表有推荐房源,此时返回推荐房源给用户if result:print('-----使用推荐系统,获取推荐房源给用户-----')for tuijian_hid, tuijian_num in result:tuijian_house = House.query.get(int(tuijian_hid))tuijian.append(tuijian_house)# 第二种情况,没有推荐的返回值,代表推荐房源为空列表,此时返回同小区的房源给用户else:print('-----使用普通推荐系统,获取同小区的房源给用户-----')putong_tuijian = House.query.filter(House.address==house.address).order_by(House.liulanliang.desc()).all()if len(putong_tuijian) > 6:tuijian = putong_tuijian[:6]else:tuijian = putong_tuijian# 没有在登陆状态下else:print('-----使用普通推荐系统,获取同小区的房源给用户-----')putong_tuijian = House.query.filter(House.address == house.address).order_by(House.liulanliang.desc()).all()if len(putong_tuijian) > 6:tuijian = putong_tuijian[:6]else:tuijian = putong_tuijianreturn render_template('detail_page.html', house=house, sheshi=sheshi_list, tuijian=tuijian)

源代码

链接:https://pan.baidu.com/s/1oBlP7B52Kp9mcqoIeHLX7Q
提取码:yovx
复制这段内容后打开百度网盘手机App,操作更方便哦

python flask智能租房项目——详情页相关推荐

  1. python flask智能租房项目——首页

    初始化项目 app.py from flask import Flask from settings import Config, dbapp = Flask(__name__)app.config. ...

  2. python flask智能租房项目——用户中心

    注册功能 1. 后端接⼝设计 接⼝描述 接⼝参数 请求⻚⾯ ⽤户中⼼⻚--注册 请求⽅式 POST 请求地址 /register 返回数据 json数据 {'valid': '1', 'msg': ' ...

  3. 接口测试平台代码实现26:项目详情页设计

    本节我们要设计项目详情页.按照我们之前的设计,项目详情页至少要包括3个部分: 接口库 :难度 ***  (接口导入/调试) 用例设置 :难度 ***** (用接口库的接口组成各种用例/执行/报告/监控 ...

  4. Python Flask框架建立项目

    Python Flask框架建立项目 ECharts实现全国空气质量查询 Python Flask框架建立项目   Flask项目建立   Flask项目编程 Python 爬虫爬取空气质量数据 Ec ...

  5. flask项目详情页后端,前端逻辑梳理

    详情页,有几块是可以重复用的,一块是左上角的网站标志,一个是右上角和右侧分别的注册和排行,还有就是下面的简价. 新闻详情页有这个,新闻列表页也有. 所以如何抽取模板呢? 张大山那里如果实现呢?那里应该 ...

  6. Python爬虫淘宝商品详情页价格、类似数据

      在讲爬取淘宝详情页数据之前,先来介绍一款 Chrome 插件:Toggle JavaScript (它可以选择让网页是否显示 js 动态加载的内容),如下图所示: 当这个插件处于关闭状态时,待爬取 ...

  7. 十二、Vue项目 - 详情页动态路由、banner布局和公用图片画廊组件拆分

    我是一个小菜鸡啊小菜鸡,但是小菜鸡要继续学新东西啊,新的一周加油吧!!! 文章目录 配置动态路由 banner.vue 公用图片画廊组件拆分 src下新建common文件夹 banner.vue中使用 ...

  8. Python Flask web 项目零改动迁移至阿里云函数计算

    引言 最近尝试了一下阿里云的函数计算,整体感觉很好,主要是省钱!下面就简单聊一下,如何将 Python Flask 的 web 项目迁移至函数计算. 创建一个银行卡校验的 RestAPI 文件名:in ...

  9. 爬取京东笔记本电脑销量榜每件商品详情页url,并存入云服务器中的mysql库

    文章目录 一.目的分析 二.爬取页面商品所有详情页链接 1.爬取href链接 2.将数据存入数据库 完整代码: 三.多线程优化版已完成 (多线程优化)爬取京东笔记本电脑销量榜data-sku(商品id ...

  10. 白屏优化_今日头条品质优化 图文详情页秒开实践

    背景 作为一个内容类应用,看新闻读资讯一直是头条用户的核心需求,页面的打开速度直接关系到用户使用头条的核心体验,在头条中,为了更多的承载足够丰富的样式和逻辑下保持多端体验的统一,详情页的内容我们是通过 ...

最新文章

  1. 百度工具栏不显示出来_解决win10系统桌面应用图标显示不出来的问题
  2. js关闭窗口无提示,不支持FF
  3. 互相封杀8年后,阿里终于挖开腾讯12亿流量金矿?
  4. intelli idea新建无scala class选项解决方案
  5. 需求用例分析之九:序列图
  6. apache apr介绍
  7. SAP License:利润中心设计思路
  8. 在苹果Mac上Word、Excel 界面变黑如何解决?
  9. java+oracle+ojdbc14_请教:使用ojdbc5.jar作为驱动jar包无法正常连接oracle数据库,而使用ojdbc14.jar却可以正常连接?...
  10. 计算机在护理专业中的论文题目,护理专业论文格式(通用模板)
  11. QuickCHM 2.6中“不支持此接口”错误的解决
  12. 手把手教你用移远M26/BC28的 MQTT协议 对接阿里云IoT平台
  13. Java程序员的职业规划是什么?叩丁狼的建议
  14. [Python从零到壹] 五十九.图像增强及运算篇之图像锐化Scharr、Canny、LOG实现边缘检测
  15. checkpoint NGFW 实验(一)
  16. 电脑系统常见进程-进程管理
  17. 大数据世界中的新技术
  18. 微信小程序单页开发之 min-cli
  19. 融会贯通,并行不悖丨2022年8月《中国数据库行业分析报告》发布!
  20. Gradle 学习 ----Gradle 进阶说明

热门文章

  1. 非线性系统线性化过程
  2. 【Android 四大组件之Content Provider】一文吃透 BroadcastReceiver 广播接收器
  3. CAD工具——导出JPG
  4. 一连三问 !!! 什么是内存对齐?内存对齐的原因是什么?内存对齐的好处是什么?
  5. 腾讯推出微信公众平台企业服务平台风铃
  6. awesomium This view has carshed!(MarkdownPad2)
  7. 处理 Win 10 开机后输入法不加载问题
  8. voip|网络电话,软件实现电信座机
  9. 内定抽奖小程序_微信抽奖小程序抽到奖品真的免费吗?
  10. Liquibase修改表字段