django Highcharts制作图表--显示CPU使用率

发布时间:2018-06-24 20:02:45编辑:admin阅读(6770)

    Highcharts 是一个用纯JavaScript编写的一个图表库。

    Highcharts 能够很简单便捷的在web网站或是web应用程序添加有交互性的图表

    Highcharts 免费提供给个人学习、个人网站和非商业用途使用。


    访问官网:

    https://www.hcharts.cn/

    进入下载页面:

    https://www.hcharts.cn/download

    下载6.10版本

    blob.png

    解压Highcharts-6.1.0.zip文件,访问里面的index.htm文件。

    点击Time series, zoomable

    blob.png

    页面效果如下:

    blob.png

    这个,就是接下来django需要用的模板。

    它在目录Highcharts-6.1.0\examples\line-time-series里面,编辑line-time-series目录下的index.htm文件

    注意这一行:

    'https://cdn.rawgit.com/highcharts/highcharts/057b672172ccc6c08fe7dbb27fc17ebca3f5b770/samples/data/usdeur.json',

    它是图表需要的json数据,打开这个json链接,将网页内容复制,使用json格式化工具处理,效果如下:

    blob.png

    如果谷歌浏览器,安装插件JSON Formatter,就可以得到上面的效果。

    它的数据格式一个大的列表,里面每一个元素都是小列表。

    列表第一个值,是一个时间戳,第二个是具体的值。打开站长工具的时间戳转换,链接如下:

    https://tool.lu/timestamp/

    输入数值1167609600000,点击转换

    blob.png

    很明显,时间不对。为什么呢?因为它是毫秒

    选择毫秒,再次点击转换,时间就对了。

    blob.png


    那么django需要输出,指定格式的json数据,才能展示正确的图表。


    数据从何而来呢?自己造呗!

    下面将演示,如何展示一个CPU使用率的图表。

    在项目根目录创建文件monit_system.py,它能统计系统的CPU使用率,内存使用情况。

    统计完成之后,将对应的数值插入到MySQL中。它会插入30条记录,每隔10秒采集一次。

    代码如下:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import pymysql
    import gevent
    import time
    import psutil
    
    #解决wind10错误OSError: raw write() returned invalid length
    import win_unicode_console
    win_unicode_console.enable()
    
    class MyPyMysql:
        def __init__(self, host, port, username, password, db, charset='utf8'):
            self.host = host  # mysql主机地址
            self.port = port  # mysql端口
            self.username = username  # mysql远程连接用户名
            self.password = password  # mysql远程连接密码
            self.db = db  # mysql使用的数据库名
            self.charset = charset  # mysql使用的字符编码,默认为utf8
            self.pymysql_connect()  # __init__初始化之后,执行的函数
    
        def pymysql_connect(self):
            # pymysql连接mysql数据库
            # 需要的参数host,port,user,password,db,charset
            self.conn = pymysql.connect(host=self.host,
                                        port=self.port,
                                        user=self.username,
                                        password=self.password,
                                        db=self.db,
                                        charset=self.charset
                                        )
            # 连接mysql后执行的函数
            self.asynchronous()
    
        def getCPUstate(self,interval=1):
            cpu = psutil.cpu_percent(interval)
            return cpu
    
        def getMemorystate(self):
            phymem = psutil.virtual_memory()
            cur_mem = phymem.percent
            mem_rate = int(phymem.used / 1024 / 1024)
            mem_all = int(phymem.total / 1024 / 1024)
    
            line = {
                'cur_mem': cur_mem,
                'mem_rate': mem_rate,
                'mem_all': mem_all,
            }
    
            return line
    
        def run(self):
            # 创建游标
            self.cur = self.conn.cursor()
            # 定义sql语句
            sql = "insert into blog_system_monit(cpu,cur_mem,mem_rate,mem_all,create_time,time_stamp) values (%s,%s,%s,%s,%s,%s)"
            print(sql)
    
            # 定义数据
            cpu = self.getCPUstate()  # cpu使用率
            mem = self.getMemorystate()  # 内存info信息
            mem_rate = mem['mem_rate']  # 内存使用率
            cur_mem = mem['cur_mem']  # 当前使用内存
            mem_all = mem['mem_all']  # 总内存
            struct_time = time.localtime()
            create_time = time.strftime("%Y-%m-%d %H:%M:%S", struct_time)  # 转换为标准时间
            t = time.time()  # 当前时间戳
            time_stamp = int(round(t * 1000))  # 转换为毫秒的时间戳
    
            print((cpu, cur_mem,mem_rate, mem_all,create_time,time_stamp))
    
            # 执行插入一行数据,如果插入多行,使用executemany(sql语句,数据(需一个元组类型))
            content = self.cur.execute(sql,(cpu,cur_mem,mem_rate,mem_all,create_time,time_stamp))
            if content:
                print('插入ok')
    
            # 提交数据,必须提交,不然数据不会保存
            self.conn.commit()
    
        def asynchronous(self):
            #执行30次协程任务
            for i in range(0,30):
                time.sleep(10)  # 等待10秒
                gevent.spawn(self.run())  # 执行方法
    
            self.cur.close()  # 关闭游标
            self.conn.close()  # 关闭pymysql连接
    
    if __name__ == '__main__':
        start_time = time.time()  # 计算程序开始时间
        st = MyPyMysql('127.0.0.1', 3306, 'root', '', 'db2')  # 实例化类,传入必要参数
        print('程序耗时{:.2f}'.format(time.time() - start_time))  # 计算程序总耗时

    创建表blog_system_monit

    进入django项目,修改blog目录下的models.py,内容如下:

    from django.db import models
    
    # Create your models here.
    #必须要继承models.Model类,这个固定写法。
    # 这里表示创建表blog_system_monit,blog是应用名,它会自动加上的。
    class system_monit(models.Model):
        #id自增,类型为bigint。设置为主键
        id = models.BigAutoField(primary_key=True)
        #类型为decimal(10,2),长度为10,小数点保留2位
        cpu = models.DecimalField(max_digits=10, decimal_places=2)
        #类型为int(11),11是默认长度
        cur_mem = models.IntegerField()
        mem_rate = models.DecimalField(max_digits=10, decimal_places=2)
        mem_all = models.IntegerField()
        #类型为datetime
        create_time = models.DateTimeField()
        #由于毫秒的时间戳超过了timestamp的长度,所以只能设置bigint了。
        time_stamp = models.BigIntegerField()

    在Pycharm的Terminal窗口中,输入以下命令

    python manage.py makemigrations

    python manage.py migrate


    执行完成之后,它会自动创建表blog_system_monit

    使用pycharm执行脚本monit_system.py,等待5分钟,就会插入30条数据。

    如果脚本没有报错,查看表记录,会有30条记录

    blob.png

    编辑文件views.py,增加2个视图函数

    def chart(request):
        #显示html文件
        return render(request, "chart.html")
    
    def chart_json(request):
        #读取表所有记录
        system_monit = models.system_monit.objects.all()
        data = []  # 创建一个空列表
        for i in system_monit:  # 遍历,拼横纵坐标
            #横坐标为时间戳,纵坐标为cpu使用率。注意,必须转换类型,否则数据不对。
            data.append([int(i.time_stamp),float('%.2f' % i.cpu)])
            
        print(data)
    
        isdict = json.dumps(data)  # json序列化列表
        return HttpResponse(isdict, content_type="application/json")  # 执行类型为json

    修改mysite下的urls.py,新增2个路径

    urlpatterns = [
        path('admin/', admin.site.urls),
        path('chart/', views.chart),
        path('chart_json/', views.chart_json),
    ]

    访问json的url

    http://127.0.0.1:8000/chart_json/


    blob.png

    必须保证格式,和上面cdn.rawgit.com链接的json格式一样。

    上的图片是用了JSON Formatter插件展示json数据的效果。

    否则下面的步骤不用做了!!!


    将line-time-series目录下的index.htm文件复制到django项目的templates目录下,重命名为chart.html

    在django项目的static文件夹下,创建目录Highcharts-6.1.0

    将Highcharts-6.1.0解压目录中的3个文件,复制到此目录

    修改部分代码,大家可以和index.htm对比一下,就知道修改的部分了。完整代码如下:

    <!DOCTYPE HTML>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Highcharts Example</title>
    
        <style type="text/css">
    
        </style>
        {#配置favicon.ico,解决警告Not Found: /favicon.ico#}
        {% load staticfiles %}
        <link REL="SHORTCUT ICON" HREF="{% static "images/favicon.ico" %}"/>
    </head>
    <body>
    <script src="../static/js/jquery-3.3.1.min.js"></script>
    <script src="../static/Highcharts-6.1.0/highcharts.js"></script>
    <script src="../static/Highcharts-6.1.0/modules/exporting.js"></script>
    <script src="../static/Highcharts-6.1.0/modules/export-data.js"></script>
    
    <div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
    
    <script type="text/javascript">
        {#解决显示时间少8小时问题#}
        Highcharts.setOptions({global: {useUTC: false}});
    
        $.getJSON(
            {#'https://cdn.rawgit.com/highcharts/highcharts/057b672172ccc6c08fe7dbb27fc17ebca3f5b770/samples/data/usdeur.json',#}
            '/chart_json/',
            function (data) {
    
                Highcharts.chart('container', {
                    chart: {
                        zoomType: 'x'
                    },
                    title: {
                        text: 'cpu使用率'
                    },
                    subtitle: {
                        text: document.ontouchstart === undefined ?
                            '单击并拖动绘图区域以放大' : '捏合图表放大'
                    },
                    xAxis: {
                        type: 'datetime',
    
                    },
                    {#自定义x坐标信息显示,return部分是用js拼接的,内容可以自己定义。#}
                    tooltip: {
                        formatter: function () {
                            return '<strong>' + this.series.name + ':' + this.y + '%<br/></strong>' +
                                Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x);
                        }
                    },
                    yAxis: {
                        title: {
                            text: '使用率'
                        }
                    },
                    legend: {
                        enabled: false
                    },
                    plotOptions: {
                        area: {
                            fillColor: {
                                linearGradient: {
                                    x1: 0,
                                    y1: 0,
                                    x2: 0,
                                    y2: 1
                                },
                                stops: [
                                    [0, Highcharts.getOptions().colors[0]],
                                    [1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
                                ]
                            },
                            marker: {
                                radius: 2
                            },
                            lineWidth: 1,
                            states: {
                                hover: {
                                    lineWidth: 1
                                }
                            },
                            threshold: null
                        }
                    },
    
                    series: [{
                        type: 'area',
                        name: '百分比',
                        data: data
                    }]
                });
            }
        );
    </script>
    </body>
    </html>


    项目文件结构如下:

    mysite/
    ├── blog
    │   ├── admin.py
    │   ├── apps.py
    │   ├── __init__.py
    │   ├── models.py
    │   └── views.py
    ├── manage.py
    ├── monit_system.py
    ├── mysite
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── static
    │   ├── css
    │   ├── Highcharts-6.1.0
    │   │   ├── highcharts.js
    │   │   └── modules
    │   │       ├── export-data.js
    │   │       └── exporting.js
    │   ├── images
    │   │   └── favicon.ico
    │   └── js
    │       └── jquery-3.3.1.min.js
    └── templates
        ├── chart.html
        ├── cur_time.html
        ├── detail.html
        └── index.html

    使用pycharm启动django项目,访问url

    http://127.0.0.1:8000/chart/

    页面效果如下:

    blob.png


    图标支持放大和缩小,可以看到秒级的数据,比如


    blob.png

    增加黑色主题

    打开解压路径,进入目录Highcharts-6.1.0\code\themes,里面有一个dark-unica.js文件

    在static\Highcharts-6.1.0目录下创建目录themes,将dark-unica.js文件复制到此目录

    修改char.html文件,在

    <script src="../static/Highcharts-6.1.0/modules/export-data.js"></script>

    下面一行添加如下代码,导入主题js

    {#黑色主题#}
    <script src="../static/Highcharts-6.1.0/themes/dark-unica.js"></script>

    再次访问网页,效果如下:

    blob.png


    我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=vcus7uflzabs


关键字