600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > python flask智能租房项目——详情页

python flask智能租房项目——详情页

时间:2020-03-10 20:00:38

相关推荐

python flask智能租房项目——详情页

基本信息展示

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=get2. 使⽤房源编号 通过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-/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_datafrom math import sqrt# 获取推荐表中所有的用户id"""1. 创建一个函数2. 获取推荐表中的所有用户浏览的信息, 根据用户id进行分类 ,获取所有的用户的id3. 对获取到的结果进行变形"""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 和 score3. 对获取到的数据 进行组装 {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. 获取推荐表中的全部的用户的id3. 遍历全部用户的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=get2. 使用房源编号 通过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 = mit()# 浏览记录为nullelse:# 直接将当前的hid插入到浏览记录中user.seen_id = str(hid)mit()# 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 = mit()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)mit()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)

源代码

链接:/s/1oBlP7B52Kp9mcqoIeHLX7Q

提取码:yovx

复制这段内容后打开百度网盘手机App,操作更方便哦

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。