回顾一下,继上篇介绍了(三)利用sqlite将json数据集按照表结构持久化操作,我们已经实现了从excel读取内容生成json、把json存入sqlite数据库,数据都已经有了,接下来,要开始制作网页,将整理后的数据发布到网络上以供查看。
这里呢,我们使用flask作为本项目的web框架,与此类似的还有大名鼎鼎的Django,框架只是个工具,掌握了基本功和框架原理后,用什么框架就像是一个练武之人,即会舞枪也会弄棒,如果非要做个比较的话,可以参考Flask VS Django:为什么Flask可能会更好。
本项目,使用flask,我们先利用flask,创建我们的web服务。
一,在flaskweb项目目录下,创建project.py文件
from flask import Flask
app = Flask(__name__)
app.secret_key = 'helloworldxdsds'
app.debug = True
@app.route('/projects/')
def projects():
return 'The project page'
@app.route('/about')
def about():
return 'The about page'
if __name__ == "__main__":
app.run()
Ctrl+Shift+F10运行project.py文件,可以看到Flask启动了服务:
F:\Python\Python38\python.exe F:/Python/program/PycharmProjects/flaskweb/project.py
* Serving Flask app "project" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Restarting with stat
* Debugger is active!
* Debugger PIN: 154-375-022
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
2,有三个点需要注意,第一个是运行网络服务时,需要设置app.secret_key;二是通过app.debug = True设置为调试模式,在更改了py文件或html文件后,flask自动静默重启,即时生效;三是@app.route('/projects/'),作为浏览器访问网址时的导引作用。有关falsk可以参见Flask中文网站,介绍的很详细。
3,在project.py文件中引入前面创建的操作数据库的python文件sqlitedata_util.py,目的是为了import该文件中定义的DB类,可以读取sqlite的数据表。
from sqlitedata_util import DB
4,创建展示网页用的资源,用到的echarts和bootstrap相关的js和css放在static中,展示用的needcare.html网页放在templates文件夹下。
5,在project.py中添加/needcare/的路由:
@app.route('/needcare/')
def needcare(data=None):
db = DB()
data = db.get_citys_nums_users()
special_data = db.get_special_users()
db.close()
return render_template('needcare.html', data=data, special_data=special_data)
6,创建needcare.html文件,该文件中引入静态js和css要使用url_for语法:
<link href="{{ url_for('static',filename='css/bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static',filename='css/style.css') }}" rel="stylesheet">
<script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
<script src="{{ url_for('static',filename='js/bootstrap.min.js') }}"></script>
<script src="{{ url_for('static',filename='js/scripts.js') }}"></script>
<script src="{{ url_for('static',filename='js/echarts.min.js') }}"></script>
7,为接收python后台传入到needcare.html的数据,要按照jinjia2的语法进行定义,需要注意的一点是,接收json类型的数据时,采用safe过滤器获取:
var sdata = {{data|safe }};
在网页的表格中通过解析json数据循环生成table的每一行数据时,使用{% %}进行逻辑的编写,如for循环{% for city in data.citys %},记得结尾要用{% endfor %} 结束,这是jinjia2的语法要求。下面是needcare.html的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 4, from LayoutIt!</title>
<meta name="description" content="Source code generated using layoutit.com">
<meta name="author" content="LayoutIt!">
<link href="{{ url_for('static',filename='css/bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static',filename='css/style.css') }}" rel="stylesheet">
<script src="{{ url_for('static',filename='js/jquery.min.js') }}"></script>
<script src="{{ url_for('static',filename='js/bootstrap.min.js') }}"></script>
<script src="{{ url_for('static',filename='js/scripts.js') }}"></script>
<script src="{{ url_for('static',filename='js/echarts.min.js') }}"></script>
</head>
<body>
<div class="row">
<div class="col-md-12">
<div class="container mt-5">
<table class="table table-bordered row mx-0 text-balck">
<thead class="w-100">
<tr class="row mx-0 bg-primary">
<th class="col-1">No.</th>
<th class="col-1">
城市
</th>
<th class="col-1">
员工
</th>
<th class="col-1">
温度
</th>
<th class="col-2">
异常情况说明
</th>
<th class="col-6">
备注
</th>
</tr>
</thead>
<tbody class="w-100">
{% for data in special_data %}
{% set i = loop.index0 %}
<tr class="row mx-0 bg-secondary">
<th class="col-1">{{i+1}}</td>
<td class="col-1">{{ data.city }}</td> <!--序列长度-->
<td class="col-1">{{ data.name }}</td> <!--是否最后一次迭代,是返回True-->
<td class="col-1">{{ data.temp }}</td> <!--是否第一次迭代,是返回True-->
<td class="col-2">{{ data.v1 }}</td> <!--是否第一次迭代,是返回True-->
<td class="col-6">{{ data.v2 }}</td> <!--是否第一次迭代,是返回True-->
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 1246px;height:400px;"></div>
<script type="text/javascript">
var sdata = {{data|safe }};
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: '公司人员所在城市分布'
},
tooltip: {},
legend: {
data:['人数']
},
xAxis: {
data: sdata.citys,
axisLabel:{
interval:0,//横轴信息全部显示
formatter:function(value){
return value.split("").join("\n");
}
}
},
yAxis: {},
series: [{
name: '人数',
type: 'bar',
data: sdata.numbers
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
//点击事件
myChart.on('click', function(params) {
console.log(params);
var name = params.name;
window.location.href="#"+name;
});
</script>
<div class="row">
<div class="col-md-12">
<table class="table table-bordered row mx-0 text-balck">
<thead class="w-100">
<tr class="row mx-0 bg-primary">
<th class="col-1">No.</th>
<th class="col-2">
城市
</th>
<th class="col-1">
人数
</th>
<th class="col-8">
员工
</th>
</tr>
</thead>
<tbody>
{% for city in data.citys %}
{% set i = loop.index0 %}
<tr class="row mx-0 bg-secondary">
<td class="col-1">{{i+1}}</td>
<td class="col-2" id="{{ city }}">{{ city }}</td> <!--序列长度-->
<td class="col-1">{{ data.numbers[i] }}</td> <!--是否最后一次迭代,是返回True-->
<td class="col-8">{{ data.usernames[i] }}</td> <!--是否第一次迭代,是返回True-->
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</body>
</html>
8,读取sqlite数据库的sqlitedata_util.py,里面定义了一个DB类,其中定义了查询各城市分散的员工姓名的函数、获得需要关注的员工等方法(与project.py同级):
import sqlite3
class DB:
def __init__(self):
self.conn = sqlite3.connect("sqlite/system.db.sqlite")
def get_citys_nums_users(self):
data = {}
# 创建一个游标 curson
cursor = self.conn.cursor()
sql = 'select city,count(*),group_concat(name) from day_temperature group by city'
cityusers = cursor.execute(sql).fetchall()
citys = []
numbers = []
usernames = []
for cityuser in cityusers:
citys.append(cityuser[0])
numbers.append(cityuser[1])
usernames.append(cityuser[2])
data['citys'] = citys
data['numbers'] = numbers
data['usernames'] = usernames
# 关闭游标:
cursor.close()
return data
def get_special_users(self):
data = []
# 创建一个游标 curson
cursor = self.conn.cursor()
sql = 'select city,name,temperature,flag1,v_2 from day_temperature where temperature > 36.9 or flag1 != "无" or (v_2 != "/" and length(v_2) > 0) order by city'
special_users = cursor.execute(sql).fetchall()
citys = []
numbers = []
usernames = []
for special_user in special_users:
u = {}
u['city'] = special_user[0]
u['name'] = special_user[1]
u['temp'] = special_user[2]
u['v1'] = special_user[3]
u['v2'] = special_user[4]
data.append(u)
# 关闭游标:
cursor.close()
return data
def close(self):
# 提交事物
self.conn.commit()
# 关闭连接
self.conn.close()
if __name__ == '__main__':
start = DB()
data = start.get_special_users()
start.close()
print(data)
# for i in range(len(data)):
# print(data[i])
9,最后,重新运行project.py,启动服务后,打开浏览器,访问/needcare/ 可以看到最终结果了。
http://127.0.0.1:5000/needcare/