6.新资产待审批区

阅读: 43173     评论:33

一、启用admin

前面,我们已经完成了数据收集客户端的编写和测试,下面我们就可以在admin中展示和管理资产数据了。

首先,通过python manage.py createsuperuser创建一个管理员账户。

然后,进入/assets/admin.py文件,写入下面的代码:

from django.contrib import admin
# Register your models here.
from assets import models


class NewAssetAdmin(admin.ModelAdmin):
    list_display = ['asset_type', 'sn', 'model', 'manufacturer', 'c_time', 'm_time']
    list_filter = ['asset_type', 'manufacturer', 'c_time']
    search_fields = ('sn',)


class AssetAdmin(admin.ModelAdmin):
    list_display = ['asset_type', 'name', 'status', 'approved_by', 'c_time', "m_time"]


admin.site.register(models.Asset, AssetAdmin)
admin.site.register(models.Server)
admin.site.register(models.StorageDevice)
admin.site.register(models.SecurityDevice)
admin.site.register(models.BusinessUnit)
admin.site.register(models.Contract)
admin.site.register(models.CPU)
admin.site.register(models.Disk)
admin.site.register(models.EventLog)
admin.site.register(models.IDC)
admin.site.register(models.Manufacturer)
admin.site.register(models.NetworkDevice)
admin.site.register(models.NIC)
admin.site.register(models.RAM)
admin.site.register(models.Software)
admin.site.register(models.Tag)
admin.site.register(models.NewAssetApprovalZone, NewAssetAdmin)

利用刚才创建的管理员用户,登录admin站点:

image

这里略微对admin界面做了些简单地配置,但目前还没有数据。

二、创建新资产

前面我们只是在Pycharm中获取并打印数据,并没有将数据保存到数据库里。下面我们来实现这一功能。

修改/assets/views.py文件,代码如下:

from django.shortcuts import render
from django.shortcuts import HttpResponse
from django.views.decorators.csrf import csrf_exempt
import json
from assets import models
from assets import asset_handler
# Create your views here.

@csrf_exempt
def report(request):
    """
    通过csrf_exempt装饰器,跳过Django的csrf安全机制,让post的数据能被接收,但这又会带来新的安全问题。
    可以在客户端,使用自定义的认证token,进行身份验证。这部分工作,请根据实际情况,自己进行。
    :param request:
    :return:
    """
    if request.method == "POST":
        asset_data = request.POST.get('asset_data')
        data = json.loads(asset_data)
        # 各种数据检查,请自行添加和完善!
        if not data:
            return HttpResponse("没有数据!")
        if not issubclass(dict, type(data)):
            return HttpResponse("数据必须为字典格式!")
        # 是否携带了关键的sn号
        sn = data.get('sn', None)
        if sn:
            # 进入审批流程
            # 首先判断是否在上线资产中存在该sn
            asset_obj = models.Asset.objects.filter(sn=sn)
            if asset_obj:
                # 进入已上线资产的数据更新流程
                pass
                return HttpResponse("资产数据已经更新!")
            else:   # 如果已上线资产中没有,那么说明是未批准资产,进入新资产待审批区,更新或者创建资产。
                obj = asset_handler.NewAsset(request, data)
                response = obj.add_to_new_assets_zone()
                return HttpResponse(response)
        else:
            return HttpResponse("没有资产sn序列号,请检查数据!")
    return HttpResponse('200 ok')

report视图的逻辑是这样的:

  • sn是标识一个资产的唯一字段,必须携带,不能重复!
  • 从POST中获取发送过来的数据;
  • 使用json转换数据类型;
  • 进行各种数据检查(比如身份验证等等,请自行完善);
  • 判断数据是否为空,空则返回错误信息,结束视图;
  • 判断data的类型是否字典类型,否则返回错误信息;
  • 之所以要对data的类型进行判断是因为后面要大量的使用字典的get方法和中括号操作;
  • 如果没有携带sn号,返回错误信息;

当前面都没问题时,进入下面的流程:

  • 首先,利用sn值尝试在已上线的资产进行查找,如果有,则进入已上线资产的更新流程,具体实现,这里暂且跳过;
  • 如果没有,说明这是个新资产,需要添加到新资产区;
  • 这里又分两种情况,一种是彻底的新资产,那没得说,需要新增;另一种是新资产区已经有了,但是审批员还没来得及审批,资产数据的后续报告就已经到达了,那么需要更新数据。
  • 创建一个asset_handler.NewAsset()对象,然后调用它的obj.add_to_new_assets_zone()方法,进行数据保存,并接收返回结果;
  • asset_handler是下面我们要新建的资产处理模块,NewAsset是其中的一个类。

image

为了不让views.py文件过于庞大,通常会建立新的py文件,专门处理一些核心业务。

在assets下新建asset_handler.py文件,并写入下面的代码:

import json
from assets import models


class NewAsset(object):
    def __init__(self, request, data):
        self.request = request
        self.data = data

    def add_to_new_assets_zone(self):
        defaults = {
            'data': json.dumps(self.data),
            'asset_type': self.data.get('asset_type'),
            'manufacturer': self.data.get('manufacturer'),
            'model': self.data.get('model'),
            'ram_size': self.data.get('ram_size'),
            'cpu_model': self.data.get('cpu_model'),
            'cpu_count': self.data.get('cpu_count'),
            'cpu_core_count': self.data.get('cpu_core_count'),
            'os_distribution': self.data.get('os_distribution'),
            'os_release': self.data.get('os_release'),
            'os_type': self.data.get('os_type'),

        }
        models.NewAssetApprovalZone.objects.update_or_create(sn=self.data['sn'], defaults=defaults)

        return '资产已经加入或更新待审批区!'

NewAsset类接收两个参数,request和data,分别封装了请求和资产数据,它的唯一方法obj.add_to_new_assets_zone()中,首先构造了一个defaults字典,分别将资产数据包的各种数据打包进去,然后利用Django中特别好用的update_or_create()方法,进行数据保存!

update_or_create()方法的机制:如果数据库内没有该数据,那么新增,如果有,则更新,这就大大减少了我们的代码量,不用写两个方法。该方法的参数必须为一些用于查询的指定字段(这里是sn),以及需要新增或者更新的defaults字典。而其返回值,则是一个查询对象和是否新建对象布尔值的二元元组。

三、测试数据

重启CMDB,在Client中使用python main.py report_data,发送一个资产数据给CMDB服务器,结果如下:

(venv) D:\work\2019\for_test\CMDB\Client\bin>python main.py report_data
正在将数据发送至: [http://192.168.0.100:8000/assets/report/]  ......
?[31;1m发送完毕!?[0m
返回结果:资产已经加入或更新待审批区!
日志记录成功!

再进入admin后台,查看新资产待审批区,可以看到资产已经成功进入待审批区:

image

image

这里我们显示了资产的汇报和更新日期,过几分钟后,重新汇报该资产数据,然后刷新admin中的页面,可以看到,待审批区的资产数据也一并被更新了。

image


 5.Linux下收集数据 7.审批新资产 

评论总数: 33


点击登录后方可评论

打卡完成



顺利完成



我遇到的问题,解决了蛮久的,分享一下,看看对大家有没有帮助 1.503错误,看看自己本地是不是设置了代理,把代理关闭即可 2.我也遇到了500错误 (1)我换成了用requests库请求,代码如下: --->handler.py import requests def report_data(): """ 收集硬件信息,然后发送到服务器。 :return: """ # 收集信息 info = info_collection.InfoCollection() asset_data = info.collect() # 将数据打包到一个字典内,并转换为json格式 data = json.dumps({"asset_data": asset_data}) # 根据settings中的配置,构造url url = "http://%s:%s%s" % (settings.Params['server'], settings.Params['port'], settings.Params['url']) print('正在将数据发送至: [%s] ......' % url) try: headers = {'content-type': 'application/json'} response = requests.post(url=url, data=data, headers=headers) message = response.text except Exception as e: message = "发送失败" + f" 错误原因:{e}" print(f"发送失败,错误原因:{e}") # 记录发送日志 with open(settings.PATH, 'ab') as f: log = f"发送时间:{time.strftime('%Y-%m-%d %H:%M:%S')} \t 服务器地址:{url} \t 返回结果:{message} \n" f.write(log.encode()) print("日志记录成功!") (2)views.py的代码也修改一下 @csrf_exempt def report(request): """ 通过csrf_exempt装饰器,跳过Django的csrf安全机制,让post的数据能被接收,但这又会带来新的安全问题。 可以在客户端,使用自定义的认证token,进行身份验证。这部分工作,请根据实际情况,自己进行。 :param request: :return: """ if request.method == "POST": request_body = json.loads(request.body.decode()) asset_data = request_body['asset_data'] if not asset_data: return HttpResponse("没有数据!") if not issubclass(dict, type(asset_data)): return HttpResponse("数据必须为字典格式!") # 是否携带了关键的sn号 sn = asset_data.get('sn', None) if sn: # 进入审批流程 # 首先判断是否在上线资产中存在该sn asset_obj = models.Asset.objects.filter(sn=sn) if asset_obj: # 进入已上线资产的数据更新流程 pass return HttpResponse("资产数据已经更新!") else: # 如果已上线资产中没有,那么说明是未批准资产,进入新资产待审批区,更新或者创建资产。 obj = asset_handler.NewAsset(request, asset_data) response = obj.add_to_new_assets_zone() return HttpResponse(response) else: return HttpResponse("没有资产sn序列号,请检查数据!") return HttpResponse('200 ok')



(3)asset_handler.py代码把字典中的self.data删除 class NewAsset(object): def __init__(self, request, data): self.request = request self.data = data def add_to_new_assets_zone(self): defaults = { 'asset_type': self.data.get('asset_type'), 'manufacturer': self.data.get('manufacturer'), 'model': self.data.get('model'), 'ram_size': self.data.get('ram_size'), 'cpu_model': self.data.get('cpu_model'), 'cpu_count': self.data.get('cpu_count'), 'cpu_core_count': self.data.get('cpu_core_count'), 'os_distribution': self.data.get('os_distribution'), 'os_release': self.data.get('os_release'), 'os_type': self.data.get('os_type'), } models.NewAssetApprovalZone.objects.update_or_create(sn=self.data['sn'], defaults=defaults) return '资产已经加入或更新待审批区!'



忽略我的评论吧QAQ,我发现后面是有坑的,不过能够解决



Internal Server Error: /assets/report/ sqlite3.OperationalError: no such table: assets_asset 正在将数据发送至: [http://192.168.4.101:8000/assets/report/] ...... ?[31;1m发送失败,错误原因: HTTP Error 500: Internal Server Error?[0m 日志记录成功! 这几个问题卡了好久了,请求指导下



no such table: assets_asset 这么明白的错误提示.....



ok,还有人吗 - -



NewAsset.add_to_new_assets_zone()方法并没有对ram_size的数据进行提取,之前/Client/plugins/collect_windows_info.py中收集到的内存数据的值是list中嵌套了字典, 如果不处理的话会报错。



请问为什么要 asset_data = request.POST.get('asset_data')?'asset_data'是怎么来的?



'asset_data'是我们前面report_data方法中定义数据的键。 这个实战中,数据的格式,也就是数据结构是非常重要的,必须前后一致。



刘老师您好,我执行python3 main.py report_data时报:“发送失败,错误原因: HTTP Error 500: Internal Server Error?[0m 日志记录成功!”错误,最后发现asset_data = request.POST.get('asset_data')里的参数名只有为asset_data就不会报错,但是在hanler.py中请求response = urllib.request.urlopen(url=url, data=data_encode, timeout=settings.Params['request_timeout'])的参数名应该跟Post.get()的参数名一致才行吗



正在将数据发送到[http://192.168.1.104:8000/assets/report/]..... ?[31;1m发送失败,错误原因: HTTP Error 500: Internal Server Error?[0m 日志记录成功! 有没有同学帮忙看看这个问题



同学这个问题你解决了吗,请教一下



刘江老师您好,我是按照您的教程一步步来的。模型一共有17个,按理说数据库最后有17个模型对应的17张表,但是我的多了一张表,叫assets_asset_tags。有人回复是多对多关系表。不太理解呢



多对多关系会额外生成一张中间关系表。请参考Django教程前面的章节多对多中间表详解。



小白一枚,目前只跟着实战到这里,发现内存容量无法写入新资产数据。分析传递的数据data,发现ram获取到的信息格式为{'ram': [{内存1信息},{内存2信息},......]}。刘大大的add_to_new_asset_zone()方法中,defaults字典无法直接获取内存容量,于是尝试以下代码获取到了内存容量总和,居然成功了,好开心: ram_size = 0 # 内存大小默认为0 ram = self.data.get('ram') for i in range(len(ram)): ram_size += ram[i].get('capacity') print(ram_size)



为什么我的显示和这个不一样,是不是那块配置错了



AttributeError: module 'assets.models' has no attribute 'CPU'



我也是这个问题,不知道你解决了没有,我的确在数据库没有看到这个字段的表



内存这个字段博主可以取一下



我自己瞎整了一下 1、在asset_handler.py文件中,先遍历一边“ram”这个key 即:在add_to_new_assets_zone(self):下面,直接 ram_size=0 for x in self.data.get('ram'): ram_size+=x.get("capacity") 然后在defaults里,取内存的时候就是 'ram_size': ram_size, 似乎也对。。。



正在将数据发送至: [http://127.0.0.1:8000/assets/report/]...... 发送失败,HTTP Error 500: Internal Server Error 日志记录成功! 好像是这句的问题 models.NewAssetApprovalZone.objects.update_or_create(sn=self.data['sn'], defaults=defaults)



ok 解决了



请教下,500错误怎么解决呢



我的问题是数据库配置错误,刘大的是assets我的是asset,重新迁移数据库就ok了



你好,我也遇到这个问题了,你是怎么解决的



您好,请教下,在这一步,我测试时,一直提示我:发送失败,<urlopen error [WinError 10061] 由于目标计算机积极拒绝,无法连接。<--这个错误该如何解决啊 - -搞了几天了还没搞明白,django=2.x的版本,win10系统。谢谢



怪我自己。。。方法名拼错了。。。 另外,为了方便观察错误,可以参考http://www.liujiangblog.com/course/django/120楼下回复这哥们的方法,用cmd运行client,然后再pycharm运行django。。



只是方法名拼错了?我也遇到了这个错误



您好能再具体讲讲这个错误怎么解决吗



完成



活跃的小仙女,好想认识一下,哈哈哈