(四)利用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/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容