(四)利用flask创建http服务,显示疫情数据

回顾一下,继上篇介绍了(三)利用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文件夹下。


Flask的静态文件和模板文件目录

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/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容