基于Python的疫情防控管理系统

背景与需求分析:

近年来,随着 Internet 的迅速崛起,互联网已成为收集信息的最佳渠道并逐步进入传统的流通领域,同时人们也能通过网络及时了解各类实事。

尤其是2019年12月以来,湖北省武汉市发现一种新型冠状病毒感染的肺炎病例;这种病毒感染性极强,扩散广。截止2022年6月15日17时,全国涉及达33个省,全国确诊3316582例,累计确诊 3631399例,死亡19163例。

疫情发生后,党中央、国务院高度重视,强调要把人民群众生命安全和身 体健康放在第一位,制定周密方案,组织各方力量开展防控,采取切实有效措 施,坚决遏制疫情蔓延势头。

疫苗是遏制疫情扩散的最有效手段,所以,对于符合接种条件的人员需要及时打疫苗,人员数量过多,需要提前预约才能前往接种,以免交叉感染;

但肺炎症状又与流感相似,普通人难以分辨,因此需要我们主动提交每日健康信息,和设立专门的发热门诊以便群众求医,同时, 对于疑似病例采取居家隔离等防控措施,也可能使群众心理出现问题,因此,需要设立专门的心理 热线以便群众舒缓放心。

总之,及时清晰地了解疫情的空间性、时间性,求医途径清晰,以及及时疏通人民心理困扰是战胜疫情的有力手段。

需求总结:

基于以上背景和需求分析,可以得知,疫情防控系统主要是面向公众(后文均称为用户)的,但也需要管理员维护以及发布相关信息;

用户的需求是疫情形势可视化,即可以查看当前国内各个省市的中高风险 区数量、现有本土病例数量和当天新增本土病例数量,可以查询某地是否为中 高风险地区、各地防疫和出行政策;此外还可以上报个人健康信息、预约疫苗、 查询各地发热门诊地址和心理热线。

管理员的需求是可以发布相关信息,提供用户查看。

系统架构说明:

疫情防控管理系统是基于 MVT 模型进行开发的, 具体可分为前台 (用户界 面)、首页、 后台 (管理员页面) 和数据库;其中, 用户操作有权限设置,分为 登录、未登录状态以及管理员状态。

前台:

前台的用户界面按权限划分功能如下:

未登录:新用户注册、登录、查看国内各省市的中高风险区数量、现有本 土病例和当天新增本土病例数量;

已登录:上报健康信息、预约疫苗、查询各地防疫政策和出行政策、查询 某地是否是中高风险区,查询各地发热门诊地址和心理热线;

 首页:

首页可查看全国各个省的疫情情况、国内各省市的中高风险区数量、现有本土病例、当天新增本土病例数量以及 Youtube、微博平台有关疫情的评论和疫情情绪分析;

后台:

后台管理员界面可以实现以下功能:

管理员可以发布各个省市的中高风险地区,发布可预约疫苗信息,发布当 天各个省的现有本土病例数量和当天新增本土病例数量,发布各地防疫政策和 出行政策,发布各地发热门诊地址和心理热线。 对这些数据表进行增删改查。

 

 

数据库:

首页基于 Django 下, 基于 PyMySQL 驱动下, 采用 MySQLdb 接口连接数据库,前后台采用Django 提供的自动生成的数据库访问 API,去连接数据库。

在下载 PyMySQL 驱动后,实例化 MySQLdb 对象去打开数据库连接后,通过 cursor()方法获取操作游标,再利用 cursor.execute(sq)即可操作数据表。

Django 只需配置 DATABASES 信息,即可连接到数据库,创建 Models 类, 即创建数据表,再通过控制台输入迁移语句, 即可在数据库中创建该表;通过对字段值赋值后,采用 save  ()方法保存数据到数据表中。

其中, Django 是采用ORM 框架映射数据库的表与模型中的类;

O 是 Object,也就是模型中的类对象,R 是 relation,即是映射关系, M 是 mapping,即映射;

采用 Django 的原因是:它内嵌了 ORM 框架,不需要直接面向数据库编程, 而是定义模型类,通过模型类和对象完成数据表的增删改查操作;

具体为:在 ORM 框架中,它把类和数据表进行一个映射,可以通过类和对象操作对应的数据表中的数据,该框架根据设计的类自动生成数据库中的数据表,省去建表的过程。

为了确保数据库操作的连续性和原子性,采用 pymysql.connect(配置信息) 创建唯一一个与数据库连接通道的接口,后续欲操作数据库时,需要通过该接口调用 cursor() 方法创建并返回一个新的游标对象,在接口没有关闭前,游  标对象可以反复使用,这就确保操作的连续性,而原子性则是每个不同操作创建不同的游标对象。

上面简单地介绍了系统的几个主体部分,前台、首页、后台和数据库连接, 接着讲述一下系统如何设计以及这几个部分是采用什么方式交互的;

设计思路:

这是一个疫情防控管理系统,首页、前台以及后台的设计流程几乎一致,所以,此小节仅以首页为例分析设计思路;

首页 (index.html) 是为了展示全国省份及省内直辖市疫情情况图,人口迁入迁出流动图,本土病例折线图,Youtube、微博平台有关疫情的评论和疫情情绪分析情况;

为了使数据可视化,该 index.html 将数据与页面排版、样式结合展示;

其中,页面排版在 index.html 给出,样式均在 static/login/js 文件夹下给出,数据除了从爬虫爬出来的csv 文件读取之外,还需要从数据库读取数据,每个操作调取数据表的数据的 sql 语句是一致的,考虑复用代码,主要流程是在 view.py  (专门处理数据库的函数) 里创建 index 类(对应首页),类中为每个操作创建游标对象以及调用对象的 execute  (sql 语句)去访问数据库;

因此,view.py 是专门处理逻辑业务的函数,.html 是各个功能的具体页面;按照逻辑上的业务划分,在view.py可以为每个业务(功能)创建对应的类,用来实现功能数据读取;

那么,读取到的数据如何在页面上显示,例如,用户在index.html 触发相应页面的操作按钮时,系统会去 urls.py 里寻找路由,在 urls.py 里匹配到对应的路径后,如首页的路由是 path('index/', views.index),就回去 views.py 里执行 index 类代码块,执行完发送数据,前端再接收,完成相应的前端处理 (样式),即显示在页面上;

因此,urls.py 是路由配置函数, .html 发起请求后根据 urls.py 跳转到 view.py 的功能类执行相应代码块,完成数据读取,再返回给.html 进行处理显示;

另,在开发其他功能模块时,可以直接在models.py里编写不同的类,用以创建对应的数据表,在运行台迁移后,即可直接在数据库中查看到该表;

这是由于 Django 框架实质上是一个 MVT 框架,M 层通过 settings.py 里配置 DATABASES  的数据库信息连接到数据库,根据不同类创建不同的数据表,数据表中的字段即类中的变量;

而要在.html  页面获取数据,需先通过 urls.py  里匹配到的路由对应到 views.py  里的类, 执行类的代码块,实例化 models.py 里的类对象,调用 objects.all/objects.get  (字段=字段值)获取数据库数据,返回给.html 处理显示。

综上,为了在代码上实现复用代码,分离逻辑层操作和页面数据处理显示,该系统采用基于 Django 的 MVT 设计模式进行开发。

MVT模型:

M :数据模型;本项目在 models.py 中创建数据模型后,在控制台完成迁移, 即可实现在数据库中创建对应的数据表,后期用于和数据库交互;

T :模板,表现层;本项目在.html 里处理与表现相关的决定;

V:视图,业务逻辑层;本项目中 V 充当 M 和 T 之间的桥梁,即 views.py 是 models.py  和.html  之间的桥梁, .html  发起请求,views.py  处理,调用 models.py 里的类的字段返回 views.py 中进行处理,返回结果给.html 进行显示。

最终整个系统的分层结构如下所示:

        login 文件夹下存放 csv 文件、 migrations、static 文件夹以及一些 py 文件;

        其中 csv 文件是爬取数据后形成的 csv 文件,migrantions 是存储 Django 应用中的 model 类的变化文件,static 是存放样式和图片;forms.py 是验证表单信息是否合理的函数;

        M:admin.py 是管理员后台要显示的表映射的类集合;models.py 是要注册 / 映射数据库表的类的集合;

        V:views.py 是逻辑处理.html 和 models.py 交互的函数。

        mysite 文件夹下存放的是系统配置文件;其中,urls.py 是路由配置文件,settings.py 是 Django 项目的配置文件,其中包括系统连接数据库以及项目文 件夹所在目录的绝对路径配置等;

        T:templates 文件夹下存放.html,处理返回的数据并按照样式显示;

        代码文件夹下存放的是爬取疫情相关数据的 py 文件。

数据库设计说明:

E-R图设计:

根据本系统有哪些实体对象以及实体对象间的关系 (E-R) 来设计数据库;

首先为本项目的对象设计 E-R  图,直观地表示实体类型和属性之间的关联关系:

(1) 用户实体(user) E-R 图,如图 3.1 所示:

 (2) 疫苗实体(vaccine) E-R 图,如图 3.2 所示:

 (3) 风险地区(risk_area) E-R 图,如图 3.3 所示:

 (4) 政策(policy) E-R 图,如图 3.4 所示:

 (5) 心理热线(phy_phone) E-R 图,如图 3.5 所示:

 (6) 病例(epid_case) E-R 图,如图 3.6 所示:

 (7) 发热门诊( clinic_addr) E-R 图,如图 3.7 所示:

数据表的设计:

通过设计的 E-R 图,进行数据表的设计;

1、user 表:

该表用于保存用户注册时的用户名、密码、性别、注册时间以及认证码;

2、vaccine 表:

该表用于保存疫苗的库存地址、疫苗数量以及疫苗的类型;

3、risk_areas 表:

该表用于保存风险地区的省份、城市以及区域;

4、policy 表:

该表用于保存政策的地址、防疫政策和出行政策;

5、phy_phone 表:

该表用于保存心理热线的地址以及电话号码;

6、epid_case 表:

该表用于保存省份以及该省份所对应的现有本土病例以及当天新增病例;

7、clinic_addr 表:

该表用于保存发热门诊的省份、城市、区域以及具体地址;

系统设计与实现:

本项目中,主要讲解数据的爬取,个人中心的疫苗预约功能,首页的广东省人口迁入迁出流动图、广州本土病例折线图的设计, 以及首页左侧的数据库查询语句的设计;

 

首页左侧--数据库查询语句的设计与验证:

首先讲解上述图部分是如何设计与实现的,首页左侧分别是查询全国疫情情况和省份疫情情况, 而这些数据存放在数据库的表—全国疫情情况和各省疫情情况,表中字段又包括有日期、省份、城市和相关疫情数据,这也意味着如果 使用 select * from table 这样的语句,花费在查询的时间会变多,并且查询的数据 并不是用户最需要的,因此,根据查询需要对查询条件作出限制;

查询全国疫情时,默认是查询 06.01 日的数据,所以在查询语句后需要增加限制字段 date 为 06.01 ,但如何传参却成了问题;

前文中已经获取页面默认日期 date 为 06.01,直接 SELECT * FROM 全国疫情情况 where date = date,不行,这样会使数据库匹配 date 字段值为 date,而不是 date 的值 06.01;

那么,在陆续尝试了 SELECT * FROM 全国疫情情况 where date = ‘date’和 “SELECT * FROM 全国疫情情况 where date =”+ ‘date’呢,也不行,都会报错;

但似乎出现了转机,既然可以通过+添加字段值,那么%s 是不是获取字段 值来的更容易呢,于是我尝试了“SELECT * FROM 全国疫情情况 where date = %s”%date  (和%’date’),均显示错误,错误在于 date 是个字符串,结尾有\0 的特殊字符,无法导入;

因此需要调用 MySQLdb 自带的转义方法 escape_string  () 对 date 进行转义,所以完整的查询语句应为下图所示:

验证流程,默认日期为 06.01,城市为广东,在代码块查询各省疫情情况处,打印 results,会只得到广东 06.01 的疫情情况;

 vaccine.html 疫苗预约功能的页面实现以及相关表的设计:

 在进行疫苗预约功能的实现前,我负责设计了可预约疫苗信息的表设计,即 vaccine 数据表,以及各省当天现有&当天新增的本土病例数量的表设计,即epid_case 数据表;

在 models.py 中完成 vaccine、epid_case 类的设计,通过迁移在数据库增加对应的表,后续均通过引用models 类对象获取字段值;

新建一个 vaccine.html 页面来显示预约疫苗详情;

根据 models.py 中 vaccine 类的设计,在 views.py 中创建函数 vaccine1 去取该类的字段值,并且在 urls.py 里新建路由来匹配 view.py 对应的函数;

将 vaccine.html  的数据操作请求跳到 views.py 里对应的类,该类调用 models.py 的对应类取字段值,返回到 vaccine.html 中处理并显示;

具体实现流程应为:

用户进入 vaccine.html,页面向系统请求数据,系统调用 urls.py 匹配路由,跳转到 views.py 里的 vaccine1 类,vaccine1 类中,通过实例化 models 的 vaccine 类对象调用 objects.all() 获取全部数据,并且将这些数 据返回给 vaccine.html 页面处理,vaccine.html 页面通过循环语句,对现有数量等于 0 的疫苗进行隐藏不显示,反之通过返回的数据对象中的key获取值显示在页面上;

另外,对循环输出的数据以表格形式显示,并且增加一列为“是否预约”,在数据项的最后一列处, 通过超链接的方式进行预约,成功预约则跳转成功页面,并对数据库进行数量减一的操作;

而对于预约这个功能,需要再增加一张表--user_vaccine,用来存放预约成功的用户以及所预约疫苗的信息;

在 models.py处进行类设计,在控制台进行迁移操作,最终实现在数据库中增设 user_vaccine 表;

设计数据表后,在 views.py 中增加一个类 user_update,用以对数据库进行字段值减一的操作;

同样地,vaccine.html 向系统发起数据减一请求,系统在 urls.py 中寻找匹配的路由进行转发请求;所以,在 urls.py 中添加路由项对应 views.py 的user_update 类;

系统将请求转发给 views.py 的 user_update 函数处理,先进行用户登录状态判断,在只有已登录的用户可以进行预约的前提下,调用 session  (此时 session 还存在,只有退出才失效),取该用户的姓名 user_name,以及发起数量减一时传递过来的 id、num、name、addr (vaccine 数据表中疫苗的 id、数量、名字以及预约地址);

对数量进行减一并赋值给 num1,注意,此时-1操作是 string 和 int 两个不同类型,因此,我还需要强转为 int 后将结果再强转为 string 赋值给 num1;

实例化 models.py 中 vaccine 类对象,调用 objects.get (字段=字段值) 进行匹配 vaccine 数据表中的数据项(即匹配用户所选择的疫苗—数据库中的疫苗数据行),对该表匹配行中的 vaccine_num 进行赋值更改数量,进行保存操作,即修改成功;

而输入值的获取是在 vaccine.html 发起请求时传入的,vaccine.html 页面通过循环输出值,根据所需的输入值关键字进行传递,具体是在跳转链接后+自定义参数进行传递;

传递也有讲究,如果将跳转链接传递自定义参数放错位置,会导致用户预约的疫苗与实际操作预约的疫苗不一致,比如我最开始将自定义参数放在循环外进行传递,这导致了传递的永远是数据表的最后一行数据,因此将自定义 参数放在对应数据行的最后一列处进行传递,可以实现只预约用户所选的疫苗;

另外,刚开始进行预约功能的设计时,我还考虑通过表单提交数据给 views.py 的 user_update 函数进行处理,并没有加入自定义参数时,结果是不管点击哪一个数据行的预约按钮,表单提交的都是最后一个数据行的数据,因为 数据行是通过循环输出的,输出结束后,key 对应的值就是最后一个数据行,表单提交后,views.py 通过 request.POST[‘key’]获取到的值并非用户所选的;

因此,我摒弃了表单提交的方式,采用在按钮处增设自定义参数进行传递,在 views.py 的 user_update 函数处,通过 request.GET.get  (‘key’) 进行获取值,就可以实现数据表操作的数据行即为用户所选的数据行。

首页中部—顶端设计:

在进行广东省人口迁入迁出流动图的设计前,对于页面布局中间的顶部进行设计,为了清晰地表示该页面的需求,在顶部显示“疫情数据可视化平台” 以及下面一部分显示日期时间地域和天气,以及是要展示什么时期的迁出或迁入按钮选择;

这个小节我只讲解页面数据如何获取的;

“疫情数据可视化平台”提示 title 由 h1 标签展示;时间 time、日期 date 和 天气 weather 及其图片等数据是由 index.html 里的 script 标签内的方法回馈的;

时间日期的获取方法由实例化 Date 对象引用相关方法获得;Date 对象获取 的结果包含当前年份、月份、日期以及时分秒,还可以获取当前是星期几;根据时分秒又可以显示是 am 还是pm;

最终将处理出来的值传递给 div 块,传递的方法是通过选择器来指定要传递值给哪个标签元素,如通过$(‘#time’).html(content) 指定 div 块 id 为 time 的元素,传值 content 给 time 显示;

而 content 调用fnW () 方法补齐两位数显示,使时间以 00 :00 :00 的形式 显示,fnW () 方法里将传入的 Date 对象各个 key 对应的 value 不足两位数的补 0 至补齐两位数;

至此,系统页面可以获取到当前的时间并显示,但为了显示实时时间,利用定时器 setInterval 方法每秒调用一次 function() 内部方法,每秒更新一次数据反馈给 html 更改;

setInterval () 方法按照指定的周期 1s  (1000 毫秒) 来调用 function  () 代码块,直到页面关闭才停止调用 function ();

首页的广东省人口迁入迁出流动图的设计:

首先是介绍总体设计的思路,再具体化讲解每部分实现过程;

在页面设计一个 div 块,表示用户操作模块,功能是选择迁入或迁出,以及选择时间节点,选择完点击搜索即可在页面中间显示对应流动图;

该 div 块里,设置了 ul,ul 包括两个 li,是放置提示兼选择按钮,供用户选择页面中间展示广东省人口迁入或迁出流动图;

除此之外,还在子 div 块里增设表单,在表单内提供日历选择器和搜索按钮,将数据提交给views.py 的 index 函数处理;其中提交的数据为用户选择的日期。

views.py  中 index 函数首先获取用户发起请求时,所选择的时间参数值,index.html 中提交表单的方式为get,因此,views.py 中获取方式为 request.GET(‘date’),其中获取到的数据样式如 2022-06-01,所以用户根据业务需要去处理数据即可,这里不赘述,后续用到再详细说明;

数据库中的 “广东省人口迁入情况” 和 “广东省人口迁出情况” 数据表的设计详情如下,各表字段分别对应迁入 / 迁出省份、迁入 / 迁出城市、一、二…… 十三,(此处是因为设计完成时间为十四号,因此只爬取了二零二二六月一至十三号的相关数据,包括省份、城市和人流比例);

由以上情况分析,用户选择的时间参数是 2022-06-01 样式,而数据表中的字段是一、二这样的样式,因此,要对 date 进行一定处理才可应用到 sql 语句中;

期间,我也考虑过采用字段为 0601 这样的样式,但在 sql 语句中不合理甚至不生效,所以还是对 date 进行一定处理更加方便;

图的设计是将获取到的 date 赋值给 test,因为其他板块也需要 date 进行不同的处理,为了更好地交互,采用不同变量名进行处理更合适;

test 的值如 2022-06-02,需要获取有效数位--最后两位数字 02,进行强转为str,值为二,才可以对应数据表的字段名,进而取值;

有效数位为两位,是因为具体日子如 06.10 需要获取 test[-2:]— 10 而不是 test[- 1]—0,这会导致 if 判断转错 str;

有效数位的获取方法是 test[-2:],获取 test 值为倒数第二位至倒数第一位区间的数字;

根据有效数位强转后的 str,补入 sql 语句中的 order bystr  (字段名) desc,使数据查询后按降序输出;

首先,通过 pymysql 连接数据库,参数分别为 IP 地址、数据库用户名及密码、数据库名称以及字符集;

连接到对应的数据库后,采用数据库对象 db 获取游标对象,游标对象可以具体操作数据库,通过引用 execute  (sql) 方法进行数据表的增删改查等操作;

这里的sql 语句是查询广东人口迁出情况数据表的数据,但由于页面仅展示某一天的数据,因此, 查询字段限制在迁出省份、迁出城市以及具体某一天,而具体某一天的数据由强转后的 str 提供, 也就是 t1;另外,还需要降序输出,以便在后续页面增设一个表单显示排序情况,因此, sql 语句还需要追加 order by 字段名 desc ,字段名同样由 t1 提供;

进行查询操作后,对结果进行获取;游标对象引用 fetchall 获取结果集合的所有行,赋值给 results ,创建三个数组分别对应某一天的人流比例、迁出省份、迁出城市,for 循环 results 的每一行并将对应行的每一列赋值给三个数组,至此,结果的获取结束。

数据获取结束后,将数据传给 html,通过 Django 提供的 render 函数传递,参数分别为 request  请求对象、template_name 网页对象、context 变量值 (key/value);

因此,html 直接通过 key 就可以获取到对应的value;

提前查询过数据库的总条目数为 100,因此,当 html 通过 key 获取到 value 后,此时的 value 是一个集合,因此需要通过 for 循环,通过 push 方法循环给 chart4Data 每一行取匹配数据库对应行的字段值;

 获取到的 value 详情就是城市一个集合、省份一个集合、数值一个集合;

在页面的左下角处增设一个表格,显示城市和人流比例的前十名,以便直观地展示给用户广东至某一日的人口迁出 / 迁入某个城市的人流比例情况;

但显示的数据要根据用户点击“迁入”或“迁出”按钮显示对应的详情,所以要增设点击功能传对应的值给表格显示;

由于div 块可知 (在上图展示过,不再重复),“迁出”按钮对应li 的data- value 为 1,“迁入”按钮对应 li 的 data-value 为 2,因此,对这两个 li 写一个点击事件,判断 value 是否为 1,如果是 1,则传给 chart4 函数数据为 chart4Data 迁出详情,li 的 value 以及 0,否则传给 chart4 函数数据为 chart4Data1 迁入详情,li 的 value 以及 0;

默认情况下,即用户不点击 li,则 chart4  (chart4Data,1,0) 传入迁出详情数据,li 的 value 和 0;

在表格显示数据只需传 chart4Data,但是 chart4 函数还需处理流动图的线条、流动方向等细节问题,因此 chart4 函数有多个参数传入;

由于 chart4Data 是降序查询,因此表格显示只需获取前十个即可显示广东省人口迁出/迁入其他城市的降序详情,然后再进行其他的样式处理显示str;

根据传入的 chartType 的值 0,进入判断方法,进行页面表格数据显示,并对人口流动图进行一定样式处理;

 

var option 指定图表的配置项和数据,tooltip 此处可忽略,因为还没完全完善;geo:{map:’china’}是显示定义地理坐标系geo,前提是下载了 china.js 中国地图样式,并且在 script 里引入;

label 默认是一个样式,表示显示地图省份名称,白色 10px 字体,内部靠左动态显示;

地图开启缩放和漫游;地图边框静态颜色设置;传入 s_data 线,样式在 s_data.push () 方法给出;

 根据传入的 type (即 li 的 value) 判断是迁出还是迁入,1 是迁出,2 是迁入,此处以迁出为例, 迁入就不细讲了;

创建 s_data 数组,引用 push 方法给数组的尾部添加一个或多个元素,为线条创造对应样式,线条的走势有 formtGCData () 方法给出;

 

 formtGCData () 方法传入的第一个参数是 geoCoordMap 页面地图数据,data 是 chart4Data/chart4Data1,srcNam 是广东省,dest 是 true/false,true 代表迁出,false 代表迁入;

根据 dest 判断线条走向是从广东省向外还是外向广东省,根据 data 集合长度,进行 for 循环,赋值每一条线条走向给 tGeoDt 数组,再返回给迁入/迁出线条样式代码块,进行样式美化,进而显示在页面上;

至此,页面中国地图已显示,并且附有省份数据显示,还增设了表单降序输出对应数据详情, 以及地图上层的迁入迁出线条显示;

广州本土病例折线图的设计:

关于广州本土病例折线图的页面的设计,主 div 块名为 box-right ,用于后续样式设计时,将其放置右边,子 div 块为 right-top,用于后续样式设计时,将其放置右边的顶部;

class 为 right-top 的 div 块里,有两个子 div 块,第一个 div 块 class 为 title- box,用于后续样式设计时,给其加背景图片和改变内部<h6>标签文字大小颜色;第二个 div 块 class 为 chart-box,其有子 div 块 id 为 chart3,设置 style 宽高百分比,具体数值根据页面情况设计,用于展示新增人数的折线图详情;

views.py 里对数据表“新增人数”进行查询,具体方法跟人口迁入迁出的设计一致,不再赘述;

通过 render 函数返回给 index.html  的数据信息,也同样在上一小节具体说明,不再赘述;

接收到 views.py 返回的数据,通过 key 获取相关 value,进行折线图设计,legend 是对折线图组件的相关配置,date 是对组件的解释,定义了 x 轴向右延伸、y 轴向上延伸,并且定义了date 的文字和图标距离上下左方为 0px,右方为 20px;

date 组件解释分别为新增确诊、死亡和累计治愈,颜色由 textStyle 决定;并且在常规和高亮状态下都显示标签,即 date;

date 组件还有数据级个性化拐点图形,由 symbol 决定,star 是正方形;

接下来就是 x、y 轴的设计,x 轴就是获取数据库的字段 date 显示,并且 x 轴的颜色设计为白色; y 轴没有显示设置,主要是因为新增人数、死亡与累计治愈的数量级不同,因此设计 y 轴根据值自动生成;设计 y 轴颜色为白色,去除 y 轴刻度线;

series 是折线的数据定点,name 对应相关的 data 组件,点击组件即可显示 对应折线;而 name 的值通过 data:字段名获取,因此,通过 name 确定对应组件,type 设计为折线,data:字段名获取数据表读出来的数据,定点各个数据后连线即成了一条折线;

dataZoom 则是数据区域缩放组件,防止数据过多时页面杂乱;y:24 代表该组件的长度为 24px, height:15 代表该组件的高度为 15px;

show:true 即显示图表;realtime:false 代表不是实时更新,因为数据是通过爬取的来的;

start:0 代表数据窗口范围的起始百分比为 0,end:50 代表数据窗口范围的起始百分比为 50;

 

数据的爬取:

由于爬取数据的方法几乎一致,所以只挑选其中一个进行讲解;

此处选择广东人口迁移数据爬取.py 进行讲解,运行该 py 文件的结果是生成广东人口迁出情况.csv 和广东人口迁入情况.csv 文件;

首先,选择数据爬取的链接样式为:http://huiyan.baidu.com/migration/cityrank.jsonp?dt=province&id=420000&type=move_in&date=20220601

dt:province 即省份;

id :本系统爬取的是广东省的人口迁移数据情况,因此,可以直接赋值 id=420000  (代表广东省) ,也可以根据省份名查找对应的城市 id,前提是有固 定变量可赋值,以及有可查找 id 的文件;

type:迁入迁出,move_in 或 move_out;

date: 日期,具体格式为 20220601;

前提准备:

classname 变量,赋值 province;

no 变量,赋值城市 id,或者 areaname 变量,通过引入其他文件,该文件里包含中国所有省份城市的 id,城市对应 key 查找城市 id 的value;

type 有两个值,所以用数组 mukous [ ] 储存 in、out;日期有区间,通过 datelist 列表存储;

具体流程:

先将中国所有省份、城市的 id 以 key / value 的形式存储在 CitiesCode [ ] 和 ProvinceCode [ ] 中,将 这 两 个 数 组 存 放 在 一 个 文 件 里,命 名 为 ChineseAdminiDivisionsDict.py,引入该文件;

默认数据,设置 classname 为 province、no 为城市 id、mukous 数组数值为 in、out 以及 areaname;

并通过 for 循环 mukous 数值,经过一定的处理前后生成迁入、迁出的数据文件;

如果 no 为空,则根据 areaname 引用 ChineseAdminiDivisionsDict.py 里的 CitiesCode[str(areaname)]查询默认的省份 id,赋值给 no;

进行数组判断,如果是 in,则赋值 “迁入” 给 nameofdire 变量,反之则赋值 “迁出” 给 nameofdire 变量;

创建新的 dateList 列表,即爬取的日期区间,通过 for 循环,将日期区间赋值给 dateList;

遍历 dateList 列表,进行数据爬取,设定 url 和 headers 后,发起数据请求,超时为 5s,通过爬取到的json 数据进行一定处理,选择自己想要的 key / value 进行裁剪;

创建几个数组用来存储省份名、城市名和对应日期的人流比例数值,数组的获取通过处理后的数组的 key 获取;

获取后判断此时 for 循环是先查询迁入还是迁出的数据,利用 dateframe[‘字段名’]赋值数组值;最后将这些数据行写入 csv 文件;

数据裁剪的流程是先判断爬取到的数据是怎样的,再根据 response.text[范 围]进行裁剪,裁剪完的数据是 str,采用 json.loads  () 将 str 转换为 dict,如果 dict 里有子 dict,可以通过数组名[‘外层 key’][‘内层 key’]的方式变成新的 dict ,通过新的 dict[i][‘key’]获取内层 value;

爬取链接的原始数据:

 处理完写入 csv 的文件数据:

 全国疫情数据爬取.py:

各省疫情数据爬取.py:

 疫情每日新增人数爬取:

 总结:

在疫苗预约的地方频频出错,一开始在预约按钮处设置了 function,当用户 点击则进入function 进行修改数据表字段值等操作;但由于那里是一个表格,表格的各项数据由数据表中读取后循环输出,每一列的值都是引用当下的 row 去获得,因此,如果用户点击预约后响应点击事件,传递的值是当下的 row 的值,那么由于循环输出结束,row 停在最后一行,这会导致传递的值是最后一 行数据行的值,经过验证,确实如此;

第二次写了跳转链接,直接跳转到 views.py 里的函数去处理逻辑关系,但由于我将跳转链接传递自定义参数放错位置,导致用户预约的疫苗与实际操作 预约的疫苗不一致;

错误过程如下:将自定义参数放在循环外进行传递, 这导致了传递的永远是数据表的最后一行数据;吸取经验教训和多次尝试后,我将自定义参数放在对应数据行的最后一列 处进行传递,可以实现只预约用户所选的疫苗;

另外,刚开始进行预约功能的设计时,我还考虑通过表单提交数据给 views.py 的 user_update 函数进行处理,并没有加入自定义参数时,结果是不管点击哪一个数据行的预约按钮,表单提交的都是最后一个数据行的数据,因为数据行是通过循环输出的,输出结束后,key对应的值就是最后一个数据行,表单提交后,views.py 通过 request.POST[‘key’] 获取到的值并非用户所选的;

因此,我摒弃了表单提交的方式,采用在按钮处增设自定义参数进行传递,在 views.py 的 user_update 函数处,通过 request.GET.get  (‘key’) 进行获取值,就可以实现数据表操作的数据行即为用户所选的数据行。

图 vaccine.html 中的预约按钮传值时增设自定义参数

同时也学会了 html 与 py 文件如何互传值,其中,html 传值给 py 文件是我最大的收获,尤其是 html 的值还是在循环过程中的某一个数据,这会导致初学者很难找到思路去获取值,但是不用慌张,多测试就摸索出来通过自定义参数传参给 views.py 文 件,py 文件通过 request.GET.get  (key) 的方式获取参数值进行数据表增删改查等操作。

另外,与JavaWeb 相比,基于 Django 的开发确实变得顺利,用户无需自己搭建后台,省去了很多工夫;而且 Python 语言也非常强大,爬取完的数据可以通过多种方式展现出来,为数据分析提供了强有力的技术支撑,例如,本疫情防控管理系统在首页处就采用了词云图、折线图、流动图以及地图等多种形式将数据可视化、清晰化,方便用户了解疫情发展形势和舆论风向。

 

 

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值