Zabbix-api获取值在Django页面展示

背景交代

私有云的同学要求把几个涉及录像的模块带宽每小时从zabbix获取一次,然后在django页面展示出来。由于django跟zabbix并不在一个服务器,那么就采取“zabbix上跑脚本,脚本将实时的带宽值存储到某个数据库里,然后django去数据库取值并且展示”这样的思路来解决问题。

python3 + Django 2.1.1
APP:accessgateway

建立数据库

首先需要先建立数据模型,在app下的models.py里添加如下:

1
2
3
4
5
6
7
8
9
10
#这里是数据模型
class lbmrs(models.Model):
host = models.CharField(verbose_name='MRS服务器名称',max_length=50)
inbandwidth = models.FloatField(verbose_name='入网带宽')
outbandwidth = models.FloatField(verbose_name='出网带宽')
date = models.DateField(auto_now_add=True)
time = models.TimeField(auto_now_add=False, auto_now=True) #获取录入时间,而且有新录入就会覆盖

def __unicode__(self):
return self.host

admin.py里添加对应的值:

1
2
3
4
5
from .models import lbmrs

class lbmrsAdmin(admin.ModelAdmin):
list_display = ('host','inbandwidth','outbandwidth','date','time')
admin.site.register(lbmrs,lbmrsAdmin)

注意!由于我们使用了TimeField,所以要修改一下setting.py:

1
2
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False

这样就能输入准确的时间,不然就是UTC时间。然后就是python manage.py makemigrationspython manage.py migrate,如果在python manage.py migrate的时候出现如下MySQL Strict Mode is not set for database connection 'default'的提示,如图:
akb48

这提示其实不重要,主要是说当前连接mysql的方式不严谨,如果要避免还是修改一下setting.py,新加一个OPTIONS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DATABASES = {
'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'ENGINE': 'django.db.backends.mysql',
'NAME': '这里是database名',
'USER': '这里是用户名',
'PASSWORD': '这里是密码',
'HOST': '这里是数据库地址',
'OPTIONS': {
"init_command": "SET sql_mode='STRICT_TRANS_TABLES'",
}
}
}

数据库方面完成,在后台界面里随便添加一个值,如下:
akb48

然后在mysql命令行看一下效果:
akb48

将值录入数据库

由于我使用的是阿里云数据库,所以要现在阿里云数据库里对django服务器和zabbix服务器同时开放白名单。

使用zabbix-api获取zabbix数值的脚本以前在 https://rorschachchan.github.io/2019/01/09/%E4%BD%BF%E7%94%A8Zabbix%E7%9A%84python-api%E5%8E%BB%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E7%9B%91%E6%8E%A7%E5%80%BC/ 里面说过了,要把获取的值保存到mysql里,只需要添加下面的代码:

1
2
3
4
5
6
7
8
#将值保存到mysql
connection = pymysql.connect(host='Mysql地址', port=3306, user='账号', passwd='密码', db='databases名称')
cursor = connection.cursor() # 创建游标
# 执行SQL,插入多行数据并返回受影响行数
sql = cursor.executemany("insert into accessgateway_ldmrs (host,inbandwidth,outbandwidth,time,date) values (%s,%s,%s,now(),curdate()))",[("第一台机器",firstin,firstout),("第二台机器",secondin,secondout),("第三台机器",thirdin,thirdout), ("第四台机器",fourthin,fourthout),("第五台机器",fivethin,fivethout)])
connection.commit() # 提交,不然无法保存修改
cursor.close() # 关闭游标
connection.close() # 关闭连接

依旧是每小时执行一次,看见mysql能成功存储到值,如图:
akb48

将数据库的值反馈到页面上

数据库现在已经取到了值,那么思路就很简单了:在views.py里设定变量,让变量可以去数据库里通过objects.values取到相应的值,然后再把这个变量通过render反应到前端页面。url.py很简单:

1
2
#前略
path(r'lb_mrs_flow.html',views.lb_mrs_flow,name="lb_mrs_flow"),

这次需求要取到以下几个值,分别是“此时的带宽”,“前一小时的带宽”,“昨天此时的带宽”。在数据库里我们也设定了date和time这两个列,所以通过限制条件就能获取到对应的值了!views.py如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import datetime
#展示服务器1.1.1.1当前流量
@login_required #需要登陆才能访问
def lb_mrs_flow(request):
today = str(datetime.date.today()) #获取当前日期
yesterday = str(datetime.date.today() - datetime.timedelta(days=1)) #获取昨天日期
hour = str(datetime.datetime.now().hour) #获取现在小时
lasthour = str((datetime.datetime.now() - datetime.timedelta(hours=1)).hour) #获取前一小时
print (today,yesterday,hour)
firstin = lbmrs.objects.values("inbandwidth").filter(host='1.1.1.1',date=today,time__istartswith=hour)) #当前值
firstin_last = lbmrs.objects.values("inbandwidth").filter(host='1.1.1.1',date=today,time__istartswith=lasthour) #前一个小时值
firstin_yes = lbmrs.objects.values("inbandwidth").filter(host='1.1.1.1',date=yesterday,time__istartswith=hour) #昨天的值
print (firstin,firstin_last,firstin_yes)

return render(request, 'lb_mrs_flow.html',{'firstin':firstin,'firstin_last':firstin_last,'firstin_yes':firstin_yes,}) #传递到前端

数据库里我们只需要inbandwidth这一列的值,所以这里就不用get()方法了,改用vales()方法,同时搭配filter()添加条件筛选。但是这样获取到的结果是一个QuerySet(查询集),元素为字典,如果要获得里面具体的值,那么就是QuerySet[0]['inbandwidth'],用上面的firstin为例子,如果想要得到具体的值就要改成下面:

1
firstin = lbmrs.objects.values("inbandwidth").filter(host='172.1.1.19',date=today,time__istartswith=hour)[0]['inbandwidth']

valuevalue_list都可以获取指定的字段,但是value_list获得是元素是元组。value_listvalue返回的并不是真正的列表字典,通俗地说,就是用的时候才真正的去数据库查,如果查询后没有使用,在数据库更新后再使用,得到的是新内容。

然后就是前端html文件lb_mrs_flow.html里写一个简单的表格,前端内容就略过不表了,直接来看结果:
akb48

可以看到如果value()方法得不到值的话,返回一个<QuerySet []>,如果是get()的话,返回就是一个错误,所以从友好度来说,还是value()更佳。

参考资料

https://blog.csdn.net/geerniya/article/details/78549182
http://yshblog.com/blog/157
https://www.kancloud.cn/hiyang/py/348229 (跨表取字段的方法)

感谢您请我喝咖啡~O(∩_∩)O,如果要联系请直接发我邮箱chenx1242@163.com,我会回复你的
-------------本文结束感谢您的阅读-------------