Django 配合Echarts绘制主机图形
Posted lyshark
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django 配合Echarts绘制主机图形相关的知识,希望对你有一定的参考价值。
在前面我总结了关于DjangoAdmin的使用技巧,利用DjangoAdmin这个后台管理功能,自己定制页面可以完成非常多的功能,下面我们将重点研究主机图形的绘制,展示和报表等功能的具体实现步骤,这里也算是个人的一点点经验。
Django 定制文章链接:https://www.cnblogs.com/LyShark/p/12119539.html
在线JS有些过期了,懒得改了,过期的话引入这个吧:
https://www.blib.cn/cdn/jquery.js
https://www.blib.cn/cdn/echarts.js
https://www.blib.cn/cdn/bootstrap3.css
继续定制增加功能
urls.py
from django.contrib import admin
from django.urls import path
from MyWeb import views
urlpatterns = [
path('', admin.site.urls),
path("grup/",views.grup)
]
views.py
from django.shortcuts import render,HttpResponse
def grup(request):
if request.method == "POST":
StartData = request.POST.get("StartData")
EndData = request.POST.get("EndData")
sel = request.POST.get("selec")
print(StartData,EndData,sel)
return render(request,"grup.html")
grup.html
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% block content %}
<form action="/grup/" method="post">
开始时间: <input type="datetime-local" name="StartData" />
结束时间: <input type="datetime-local" name="EndData" />
<select name="selec">
<option value="CPU">CPU负载</option>
<option value="Mem">内存负载</option>
</select>
<input type="submit" value="查询">
</form>
<br>
<div id="main" style="width: 90%; height: 300px; border: 1px solid #eecc11; padding: 40px">
<script src="http://echarts.baidu.com/dist/echarts.min.js"></script>
<script>
var mychart = echarts.init(document.getElementById("main"));
var option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line'
}]
};
mychart.setOption(option)
</script>
{% endblock %}
更新数据
批量填充数据.
from django.db import models
class CPU(models.Model):
id = models.AutoField(primary_key = True)
Address = models.CharField(max_length=64)
Times = models.CharField(max_length=64)
load5 = models.CharField(max_length=64)
load10 = models.CharField(max_length=64)
load15 = models.CharField(max_length=64)
import os,sys,sqlite3
import time,psutil,datetime
def GetCPU_Load(addr):
dic = {}
times = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M")
cpu = psutil.cpu_percent(interval=None,percpu=True)
dic["Address"] = addr
dic["Times"] = times
dic["load5"] = cpu[0]
dic["load10"] = cpu[1]
dic["load15"] = cpu[2]
return dic
if __name__ == "__main__":
conn = sqlite3.connect("db.sqlite3")
cursor = conn.cursor()
while True:
dic = GetCPU_Load("192.168.1.1")
insert = 'insert into MyWeb_cpu(Address,Times,load5,load10,load15) values("{}","{}","{}","{}","{}")'. format(dic["Address"],dic["Times"],dic["load5"],dic["load10"],dic["load15"])
print(insert)
cursor.execute(insert)
conn.commit()
time.sleep(1)
来看下数据库的设计。
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% load static %}
{% block title %}{{ site_title|default:_('Django site admin') }}{% endblock %}
{% block content %}
<form action="/cpu/" method="post">
主机地址: <input type="text" name="Address" />
开始时间: <input type="datetime-local" name="StartData" />
结束时间: <input type="datetime-local" name="EndData" />
<select name="selec">
<option value="CPU">CPU负载</option>
<option value="Mem">内存负载</option>
</select>
<input type="submit" value="查询">
</form>
{{ time }}
{{ load }}
from django.shortcuts import render,HttpResponse
from MyWeb import models
import time,datetime
def cpu(request):
if request.method == "POST":
times = []
load = []
Address = request.POST.get("Address")
StartData = request.POST.get("StartData")
EndData = request.POST.get("EndData")
ret = models.CPU.objects.raw('select * from MyWeb_cpu where Times>="{}" and Times <="{}";'.
format(StartData,EndData))
for item in ret:
times.append(item.Times.split("T")[1])
load.append(item.load5)
return render(request,"index.html",{"time":times,"load":load})
有个问题,没有解决,可能得用json发数据。
最后没找到解决方法,应该是要用json序列化一下就好,不管了,直接用以下代码吧,能力有限,不是专门干django的,随便玩玩不要太在意。
<!--name: index.html-->
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% load static %}
{% block title %}{{ site_title|default:_('Django site admin') }}{% endblock %}
{% block content %}
<form action="/cpu/" method="post">
开始时间: <input type="datetime-local" name="StartData" />
结束时间: <input type="datetime-local" name="EndData" />
<select name="selec">
<option value="CPU">CPU Load5 负载</option>
</select>
<input type="submit" value="检索图形">
</form>
<div id="main" style="width: 90%; height: 300px; border: 1px solid #eecc11; padding: 40px">
<script src="http://echarts.baidu.com/dist/echarts.min.js"></script>
<script>
var mychart = echarts.init(document.getElementById("main"));
var option = {
grid:{
top:"50px",
left:"50px",
right:"15px",
bottom:"50px"
},
xAxis: {
type: 'category',
data: {{ cpu_data }}
},
yAxis: {
type: 'value'
},
series: [{
type: 'line',
data: {{ cpu_data }}
}]
};
mychart.setOption(option)
</script>
{% endblock %}
加上IP地址,更加完美
上方form表单提交后会自动清除表单内容,如果不想清空,可以使用ajax方式提交,或使用一下方法来完成.
{% block content %}
<form action="/fw/" method="post" target="not_iframe">
<input type="text" name="user"/>
<input type="submit" value="提交">
</form>
<iframe id="id_iframe" name="not_iframe" style="display:none;"></iframe>
{% endblock %}
本机仪表盘
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% load static %}
{% block title %}{{ site_title|default:_('Django site admin') }}{% endblock %}
{% block content %}
<div id="cpuChart" style="width: 32%; height: 380px; border: 1px solid #dddddd; float:left; margin-right: 8px;"></div>
<div id="memChart" style="width: 32%; height: 380px; border: 1px solid #dddddd; float:left; margin-right: 8px;"></div>
<div id="diskChart" style="width: 32%; height: 380px; border: 1px solid #dddddd; float:left; margin-right: 8px;"></div>
<script src="https://cdn.bootcss.com/echarts/4.6.0/echarts.min.js"></script>
<script>
var cpuChart = echarts.init(document.getElementById("cpuChart"));
var option = {
series: [
{
type: 'gauge',
detail: {formatter: '{value}%'},
data: [{value: 44, name: 'CPU 利用率'}]
}
]
};cpuChart.setOption(option, true);
</script>
<script>
var memChart = echarts.init(document.getElementById("memChart"));
var option = {
series: [
{
type: 'gauge',
detail: {formatter: '{value}%'},
data: [{value: 25, name: '内存利用率'}]
}
]
};memChart.setOption(option, true);
</script>
<script>
var diskChart = echarts.init(document.getElementById("diskChart"));
var option = {
series: [
{
type: 'gauge',
detail: {formatter: '{value}%'},
data: [{value: 18, name: '磁盘使用量'}]
}
]
};diskChart.setOption(option, true);
</script>
{% endblock %}
制作动态监控平台
绘图
<div id="echo" style="width: 100%; height: 400px; "></div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" type="text/javascript"></script>
<script src="https://cdn.bootcss.com/echarts/4.6.0/echarts.min.js"></script>
<script type="text/javascript" charset="UTF-8">
var display = function(time,cpu1,cpu5,cpu15){
var echo =echarts.init(document.getElementById("echo"));
var option = {
// tooltip 鼠标放上去之后会自动出现坐标
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},// toolbox = 菜单栏中的各种小功能
toolbox: {
feature: {
dataZoom: {
yAxisIndex: 'none'
},
restore: {},
saveAsImage: {}
}
},
legend: {
data: [ '1分钟负载', '5分钟负载', '15分钟负载']
},
xAxis: {
type: 'category',
data: time
},
yAxis: {
type: 'value'
},
series: [
{
name: "1分钟负载",
stack: "总量",
data: cpu1,
type: 'line'
},
{
name: "5分钟负载",
stack: "总量",
data: cpu5,
type: 'line'
},
{
name: "15分钟负载",
stack: "总量",
data: cpu15,
type: 'line'
}
]
};
echo.setOption(option,true);
};
</script>
另一种刷新式绘图
<script type="text/javascript" src="https://cdn.bootcss.com/echarts/4.6.0/echarts.min.js"></script>
<div id="main" style="height:500px;width:1200px;border:1px solid #eecc11;padding:10px;"></div>
<script type="text/javascript" charset="UTF-8">
var display = function(time,cpu){
// 负责初始化绘图画布
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption({
title: {
text: '监控系统CPU资源'
},
tooltip: {},
xAxis: {
data: []
},
yAxis: {},
series: [{
name: 'cpu',
type: 'line',
data: []
}]
});
// 下方就是给指定字段填充数据
myChart.setOption({
xAxis: {
data: time
},
series: [{
name: 'cpu', // 根据名字对应到相应的系列
data: cpu
}]
});
};
// 首次显示加载动画
myChart.showLoading();
</script>
数据处理
// 负责对参数的解析
var time =["","","","","","","","","",""];
var cpu1 = [0,0,0,0,0,0,0,0,0,0];
var cpu5 = [0,0,0,0,0,0,0,0,0,0];
var cpu15 = [0,0,0,0,0,0,0,0,0,0];
var update = function(recv){
time.push(recv.response[0]);
cpu1.push(parseFloat(recv.response[1]));
cpu5.push(parseFloat(recv.response[2]));
cpu15.push(parseFloat(recv.response[3]));
if(time.length >=10){
time.shift();
cpu1.shift();
cpu5.shift();
cpu15.shift();
display(time,cpu1,cpu5,cpu15)
}
};
图形更新
$(
function () {
fetchData();
setInterval(fetchData, 1000);
}
);
function fetchData(){
$.ajax({
url:"/_ajax/",
type:"GET",
dataType: 'json',
success:function (recv) {
update(recv);
}
})
}
view.py
from django.shortcuts import render,HttpResponse
import os,subprocess,time,json
def index(request):
return render(request,"index.html")
def ajax(request):
if request.method == "GET":
data = []
data.append(time.strftime("%M:%S", time.localtime()))
for key in ["system.cpu.util[,,avg1]", "system.cpu.util[,,avg5]", "system.cpu.util[,,avg15]"]:
cmd = "C:/get.exe -s {} -p {} -k {}".format("192.168.1.20", "10050", key)
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
data.append(float(proc.stdout.readlines()[0].split()[0]))
return HttpResponse(json.dumps({"response":data}))
urls.py
from django.contrib import admin
from django.urls import path
from MyWeb import views
urlpatterns = [
path('admin/', admin.site.urls),
path("cpu/",views.index),
path("_ajax/",views.ajax)
]
可能效果不是很明显,你可以稍微改一下代码。
def ajax(request):
if request.method == "GET":
data = []
data.append(time.strftime("%M:%S", time.localtime()))
data.append(random.randint(1,100))
data.append(random.randint(100, 200))
data.append(random.randint(23, 90))
return HttpResponse(json.dumps({"response":data}))
// 负责对参数的解析
var time =["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""];
var cpu1 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var cpu5 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var cpu15 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var update = function(recv){
time.push(recv.response[0]);
cpu1.push(parseFloat(recv.response[1]));
cpu5.push(parseFloat(recv.response[2]));
cpu15.push(parseFloat(recv.response[3]));
if(time.length >=40){
time.shift();
cpu1.shift();
cpu5.shift();
cpu15.shift();
display(time,cpu1,cpu5,cpu15)
}
};
除了可以监控系统负载外,还可以监控网卡,监控内存等,原理都是一样的,网卡监控代码。
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% load static %}
{% block content %}
<div id="main" style="width: 100%; height: 400px;"></div>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/echarts/4.6.0/echarts.min.js"></script>
<script type="text/javascript" charset="UTF-8">
var display = function(){
var main =echarts.init(document.getElementById("main"));
var option = {
// tooltip 鼠标放上去之后会自动出现坐标
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},// toolbox = 菜单栏中的各种小功能
toolbox: {
feature: {
dataZoom: {
yAxisIndex: 'none'
},
restore: {},
saveAsImage: {}
}
},
legend: {
data: [ '网卡入口流量', '网卡出口流量']
},
// 负责绘图的配置
xAxis: {
type: 'category',
data: [1,2,3,4,5,1,2,3,4,5]
},
yAxis: {
type: 'value'
},
series: [
{
name: "网卡入口流量",
stack: "总量",
data: [1,2,3,4,5,1,2,3,4,5],
type: 'line',
areaStyle: {}
},
{
name: "网卡出口流量",
stack: "总量",
data: [1,2,3,4,5,1,2,3,4,5],
type: 'line',
areaStyle: {}
}
]
};
main.setOption(option,true);
};
display()
</script>
{% endblock %}
制作网站流量统计页面
import os,sys
def log(path):
key = []
value = []
for item in fp.readlines():
date = item.split()[3]
HourData = date.split(":")[1] + ":" + date.split(":")[2]
if item.split()[9] != "-" and item.split()[9] != '"-"':
SendByte = int(item.split()[9])
key.append(HourData)
value.append(SendByte)
return dict(zip(key,value))
fp = open("c://access.log","r")
dic = log(fp)
针对Web服务的流量统计 上面代码只能统计出所有的流量,无法叠加,可以以IP为例进行流量叠加。
import os,sys
def Count_IP_And_Flow(file):
addr = {} # key 保存当前的IP信息
flow = {} # value 保存当前IP流量总和
Count= 0 # 针对IP地址的计数器
with open(file) as f:
contexts = f.readlines()
for line in contexts:
if line.split()[9] != "-" and line.split()[9] != '"-"':
size = line.split()[9]
ip_attr = line.split()[0]
Count = int(size) + Count
if ip_attr in addr.keys():
addr[ip_attr] = addr[ip_attr] + 1
flow[ip_attr] = flow[ip_attr] + int(size)
else:
addr[ip_attr] = 1
flow[ip_attr] = int(size)
return addr,flow
if __name__ == "__main__":
Address,OutFlow = Count_IP_And_Flow("c://access.log")
print("地址计数:{} ---> 流量计数:{}".format(Address,OutFlow))
上面的代码,稍微修改一下就能统计时间与流量的关系。
def Count_IP_And_Flow(file):
addr = {} # key 保存当前的IP信息
flow = {} # value 保存当前IP流量总和
Count= 0 # 针对IP地址的计数器
with open(file) as f:
contexts = f.readlines()
for line in contexts:
if line.split()[9] != "-" and line.split()[9] != '"-"':
size = line.split()[9]
temp = line.split()[3]
ip_attr = temp.split(":")[1] + ":" + temp.split(":")[2]
Count = int(size) + Count
if ip_attr in addr.keys():
addr[ip_attr] = addr[ip_attr] + 1
flow[ip_attr] = flow[ip_attr] + int(size)
else:
addr[ip_attr] = 1
flow[ip_attr] = int(size)
return addr,flow
if __name__ == "__main__":
Address,OutFlow = Count_IP_And_Flow("c://access.log")
print("流量计数:{}".format(Address,OutFlow))
接着是绘图
统计IP出现的次数。
def IP_Count(file):
ip = {}
with open(file) as f:
for i in f.readlines():
ip_attr = i.strip().split()[0]
if ip_attr in ip.keys():
ip[ip_attr] = ip[ip_attr] + 1
else:
ip[ip_attr] = 1
print(ip)
IP_Count("c://access.log")
饼状图绘制方法
饼状图的绘制: 统计目标主机网页状态码,与个数,并绘制饼状图,饼图和其他图不太一样,绘制起来蛮烦一些。
from django.shortcuts import render
import json
def Count_Flag_And_Flow(file):
list = []
flag = {}
with open(file) as f:
contexts = f.readlines()
for line in contexts:
it = line.split()[8]
list.append(it)
list_num = set(list)
for item in list_num:
num = list.count(item)
flag[item] = num
return flag
def index(request):
Address = Count_Flag_And_Flow("c://access.log")
print(Address)
return render(request,"index.html",{"data":json.dumps(Address)})
from MyWeb import views
urlpatterns = [
path('admin/', admin.site.urls),
path("log/",views.index)
]
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% load static %}
{% block content %}
<div id="main" style="width:50%; height: 300px"></div>
<script src="https://www.blib.cn/cdn/echarts.js" type="text/javascript"></script>
<script src="https://www.blib.cn/cdn/jquery.js" type="text/javascript"></script>
<script type="text/javascript" charset="UTF-8">
var kv = new Array();
kv = {{ data | safe }}
var test = new Array();
for(var logkey in kv){
test.push( {value:kv[logkey], name:logkey} )
}
var display = function(){
var main = echarts.init(document.getElementById("main"));
var option = {
legend: {
orient: 'vertical',
left: 'left',
},
series: [
{
type: 'pie',
radius: '70%',
center: ['50%', '50%'],
detail: {formatter:'{value}'},
data: test
}
]
};
main.setOption(option,true);
};
display();
</script>
{% endblock %}
加上框架看效果。
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<div class="panel panel-primary" style="width: 60%;height: 50%">
<div class="panel-heading">
<h3 class="panel-title">网站访问状态统计</h3>
</div>
<div class="panel-body">
这是一个基本的面板
</div>
</div>
来,搞事
<link rel="stylesheet" href="https://www.blib.cn/cdn/bootstrap3.css">
<div class="panel panel-primary" style="width: 40%;height: 30%">
<div class="panel-heading">
<h3 class="panel-title">网站访问状态统计</h3>
</div>
<div class="panel-body">
<div id="main" style="width:100%; height: 300px"></div>
</div>
</div>
柱状图绘制方法
设备类型统计: 统计设备的类型,例如Windows linux 等,这里我们接着上面的做吧,先来改布局。
{% block content %}
<link rel="stylesheet" href="https://www.blib.cn/cdn/bootstrap3.css">
<div class="panel panel-primary" style="width: 40%;height: 30%;float: left">
<div class="panel-heading">
<h3 class="panel-title">网站访问状态统计</h3>
</div>
<div class="panel-body">
<div id="main" style="width:100%; height: 300px"></div>
</div>
</div>
<div class="panel panel-primary" style="width: 58%;height: 30%; float: right">
<div class="panel-heading">
<h3 class="panel-title">网站设备类型统计</h3>
</div>
<div class="panel-body">
<div id="main1" style="width:100%; height: 300px"></div>
</div>
</div>
import os,sys
def Count_Flag_And_Type(file):
list = []
flag = {}
with open(file) as f:
contexts = f.readlines()
for line in contexts:
list.append( line.split()[12].replace("(",""))
list_num = set(list)
for item in list_num:
num = list.count(item)
flag[item] = num
return flag
if __name__ == "__main__":
a = Count_Flag_And_Type("c://access.log")
print(a)
以上是关于Django 配合Echarts绘制主机图形的主要内容,如果未能解决你的问题,请参考以下文章