背景交代
私有云的同学要求把几个涉及录像的模块带宽每小时从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
5from .models import lbmrs
class lbmrsAdmin(admin.ModelAdmin):
list_display = ('host','inbandwidth','outbandwidth','date','time')
admin.site.register(lbmrs,lbmrsAdmin)
注意!由于我们使用了TimeField
,所以要修改一下setting.py
:
1
2TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False
这样就能输入准确的时间,不然就是UTC时间。然后就是python manage.py makemigrations
和python manage.py migrate
,如果在python manage.py migrate
的时候出现如下MySQL Strict Mode is not set for database connection 'default'
的提示,如图:
这提示其实不重要,主要是说当前连接mysql的方式不严谨,如果要避免还是修改一下setting.py
,新加一个OPTIONS
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14DATABASES = {
'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'",
}
}
}
数据库方面完成,在后台界面里随便添加一个值,如下:
然后在mysql命令行看一下效果:
将值录入数据库
由于我使用的是阿里云数据库,所以要现在阿里云数据库里对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能成功存储到值,如图:
将数据库的值反馈到页面上
数据库现在已经取到了值,那么思路就很简单了:在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
15import datetime
#展示服务器1.1.1.1当前流量
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']
value
和value_list
都可以获取指定的字段,但是value_list
获得是元素是元组。value_list
和value
返回的并不是真正的列表
或字典
,通俗地说,就是用的时候才真正的去数据库查,如果查询后没有使用,在数据库更新后再使用,得到的是新内容。
然后就是前端html文件lb_mrs_flow.html
里写一个简单的表格,前端内容就略过不表了,直接来看结果:
可以看到如果value()
方法得不到值的话,返回一个<QuerySet []>
,如果是get()
的话,返回就是一个错误,所以从友好度来说,还是value()
更佳。
参考资料
https://blog.csdn.net/geerniya/article/details/78549182
http://yshblog.com/blog/157
https://www.kancloud.cn/hiyang/py/348229 (跨表取字段的方法)