1、目录结构
PS Y:\MadkingClient> tree /f
卷 netgame 的文件夹 PATH 列表
卷序列号为 ACE3-896E
Y:.
├─bin
│ NedStark.py
│ __init__.py
│
├─conf
│ │ settings.py
│ │ __init__.py
│ │
│ └─__pycache__
│ settings.cpython-35.pyc
│ __init__.cpython-35.pyc
│
├─core
│ │ api_token.py
│ │ HouseStark.py
│ │ info_collection.py
│ │ __init__.py
│ │
│ └─__pycache__
│ api_token.cpython-35.pyc
│ HouseStark.cpython-35.pyc
│ info_collection.cpython-35.pyc
│ __init__.cpython-35.pyc
│
├─logs
│ run_log
│ __init__.py
│
├─plugins
│ │ plugin_api.py
│ │ __init__.py
│ │
│ ├─linux
│ │ │ MegaCli
│ │ │ sysinfo.py
│ │ │ __init__.py
│ │ │
│ │ └─__pycache__
│ │ sysinfo.cpython-35.pyc
│ │ __init__.cpython-35.pyc
│ │
│ ├─windows
│ │ │ sysinfo.py
│ │ │
│ │ └─__pycache__
│ │ sysinfo.cpython-35.pyc
│ │
│ └─__pycache__
│ plugin_api.cpython-35.pyc
│ __init__.cpython-35.pyc
│
└─var
.asset_id
PS Y:\MadkingClient>
2、安装收集windows里硬件信息的模块
安装pywin32-221
下载地址:
https://jaist.dl.sourceforge.net/project/pywin32/pywin32/Build%20221/pywin32-221.win-amd64-py3.5.exe
安装一路下一步就可以了
安装WMI
下载地址:
https://files.pythonhosted.org/packages/f6/6b/3c15ef280e2a6244ff0635f763b86fdc113654afc1192fcea8a0109f47f8/WMI-1.4.9.win32.exe
安装一路回车就可以了
python WMI模块的使用实例
https://blog.csdn.net/zmj_88888888/article/details/8700950
turer单词写错
3、如何把数据传输都服务器?
你不知道管理员什么时候审批?
让管理员知道你把数据发给他了,
1、肯定不能存在表里,
2、存到服务器内存不行,客户端一重启就不行了,
3、写到文件里可以
4、存到数据库的临时表里面
我有一条资产要发送给服务器我把数据不能存到数据库里那我存到那里呀?
答:新资产审批区,等管理员审批完了写到数据库里
客户第二次回报的数据怎样和第一次存到数据库里面的数据如何关联?
1、可以用SN号作为关联
这个是最简单的
2、可以同过自增id
之前,我在汽车之家就没有把sn当做资产唯一值
数据更新流程
1、第一次数据存到待批准区
2、当管理员资产一批准就会把资产Id返回给客户端
3、以后客户端更新就带着服务器端给的资产ID
服务器如何把资产id返回给客户端?
1、服务端无法返回因为是一个web浏览器
2、所以他只有等只有等客户端第二次链接的时候给他一个资产ID
4、NedStark入口
#_*_coding:utf-8_*_
import os,sys,platform
#for linux
if platform.system() == "Windows":
BASE_DIR = '\\'.join(os.path.abspath(os.path.dirname(__file__)).split('\\')[:-1])
print BASE_DIR
else:
BASE_DIR = '/'.join(os.path.abspath(os.path.dirname(__file__)).split('/')[:-1])
sys.path.append(BASE_DIR)
from core import HouseStark
if __name__ == '__main__':
HouseStark.ArgvHandler(sys.argv)
#为什么叫nedstack入口文件,分析参数,手机参数,私有方法
5、HouseStark注释
#_*_coding:utf-8_*_
import info_collection
from conf import settings
import urllib,urllib2,sys,os,json,datetime
import api_token
class ArgvHandler(object):
def __init__(self,argv_list):
self.argvs = argv_list
self.parse_argv()
def parse_argv(self):
if len(self.argvs) >1:
if hasattr(self,self.argvs[1]):
func = getattr(self,self.argvs[1])
func()
else:
self.help_msg()
else:
self.help_msg()
#帮助菜单.有参数就执行,没参数打印帮助
def help_msg(self):
msg = '''
collect_data 收集硬件信息
run_forever 永远运行
get_asset_id 获取资产ID
report_asset 收集硬件信息并汇报
'''
print(msg)
def collect_data(self):
"""收集硬件信息"""
obj = info_collection.InfoCollection()
asset_data = obj.collect()
#加上括号不是类就是方法这里显然是方法,因为我给它赋了一个obj
#print asset_data
#
def run_forever(self):
pass
def __attach_token(self,url_str):
'''generate md5 by token_id and username,and attach it on the url request'''
user = settings.Params['auth']['user']
token_id = settings.Params['auth']['token']
md5_token,timestamp = api_token.get_token(user,token_id)
url_arg_str = "user=%s×tamp=%s&token=%s" %(user,timestamp,md5_token)
if "?" in url_str:#already has arg
new_url = url_str + "&" + url_arg_str
else:
new_url = url_str + "?" + url_arg_str
return new_url
#print(url_arg_str)
def __submit_data(self,action_type,data,method):
'''
send data to server
param action_type:url
param data:具体要发送的数据
param method :get/post
return:
'''
if action_type in settings.Params['urls']:
if type(settings.Params['port']) is int:
url = "http://%s:%s%s" %(settings.Params['server'],settings.Params['port'],settings.Params['urls'][action_type]) #有端口
else:
url = "http://%s%s" %(settings.Params['server'],settings.Params['urls'][action_type]) #没有端口
url = self.__attach_token(url) #端口验证
print('Connecting [%s], it may take a minute' % url)
if method == "get":
args = ""
for k,v in data.items():
args += "&%s=%s" %(k,v)
args = args[1:]
url_with_args = "%s?%s" %(url,args)
try:
req = urllib2.Request(url_with_args)
req_data = urllib2.urlopen(req,timeout=settings.Params['request_timeout'])
callback = req_data.read()
print("-->server response:",callback)
return callback
except urllib2.URLError as e:
sys.exit("\033[31;1m%s\033[0m"%e)
elif method == "post":
try:
data_encode = urllib.urlencode(data)
req = urllib2.Request(url=url,data=data_encode)
res_data = urllib2.urlopen(req,timeout=settings.Params['request_timeout'])
callback = res_data.read()
callback = json.loads(callback)
print("\033[31;1m[%s]:[%s]\033[0m response:\n%s" %(method,url,callback))
return callback
except Exception as e:
sys.exit("\033[31;1m%s\033[0m"%e)
else:
raise KeyError
#def __get_asset_id_by_sn(self,sn):
# return self.__submit_data("get_asset_id_by_sn",{"sn":sn},"get")
def load_asset_id(self,sn=None):
asset_id_file = settings.Params['asset_id']
has_asset_id = False
if os.path.isfile(asset_id_file):
asset_id = open(asset_id_file).read().strip()
if asset_id.isdigit():
return asset_id
else:
has_asset_id = False
else:
has_asset_id = False
def __update_asset_id(self,new_asset_id):
asset_id_file = settings.Params['asset_id']
f = open(asset_id_file,"wb")
f.write(str(new_asset_id))
f.close()
def report_asset(self):
obj = info_collection.InfoCollection()
asset_data = obj.collect()
"""
asset_id是干什么的?
def log_record
"""
asset_id = self.load_asset_id(asset_data["sn"])
"""
为什么要oad_asset_id,拿到文件名
第一次回报肯定没有,但是我不知道你是第几次,所以只能用这个资产id来判断
"""
if asset_id: #reported to server before
asset_data["asset_id"] = asset_id
post_url = "asset_report"
else:#first time report to server
'''report to another url,this will put the asset into approval waiting zone, when the asset is approved ,this request returns
asset's ID'''
asset_data["asset_id"] = None
post_url = "asset_report_with_no_id"
"""
首先要判断文件存在不,如果存在就判断是不是一个整数,要取资产ID
post_url是干什么的?
为了不影响全局我单独写一个URL,name是什么,是一个变量l
"""
data = {"asset_data": json.dumps(asset_data)}
response = self.__submit_data(post_url,data,method="post")
if "asset_id" in response:
self.__update_asset_id(response["asset_id"])
self.log_record(response)
"""
asset_id是干什么的?
def log_record
"""
def log_record(self,log,action_type=None):
f = open(settings.Params["log_file"],"ab")
if log is str:
pass
if type(log) is dict:
if "info" in log:
for msg in log["info"]:
log_format = "%s\tINFO\t%s\n" %(datetime.datetime.now().strftime("%Y-%m-%d-%H:%M:%S"),msg)
#print msg
f.write(log_format)
if "error" in log:
for msg in log["error"]:
log_format = "%s\tERROR\t%s\n" %(datetime.datetime.now().strftime("%Y-%m-%d-%H:%M:%S"),msg)
f.write(log_format)
if "warning" in log:
for msg in log["warning"]:
log_format = "%s\tWARNING\t%s\n" %(datetime.datetime.now().strftime("%Y-%m-%d-%H:%M:%S"),msg)
f.write(log_format)
f.close()
urllib.request read()
Windows PowerShell
版权所有 (C) 2009 Microsoft Corporation。保留所有权利。
PS C:\Users\Administrator> python
Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import urllib.request
>>> urllib.request.urlopen("http://www.baidu.com")
<http.client.HTTPResponse object at 0x0000000002C38B00>
>>> rep = urllib.request.urlopen("http://www.baidu.com")
>>> rep.read()
b'<!DOCTYPE html>\n<!--STATUS OK-->\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\
n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\
n\r\n\r\n\r\n\r\n\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\
r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\r\n \r\n\t\t\t \r\n\t\r\n\t\t\t \r\n\t\r\n\t\t\t \r\n\
t\r\n\t\t\t \r\n\t\t\t \r\n\r\n\t\r\n \r\n\t\t\t \r\n\t\r\n\t\t\t \r\n\t\r\n\t\t\t
\r\n\t\r\n\t\t\t \r\n\t\t\t \r\n\r\n\r\n\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\r\n\n<html>\n<head>\n \
n <meta http-equiv="content-type" content="text/html;charset=utf-8">\n <meta http-equiv="X-UA-Compatible" content=
"IE=Edge">\n\t<meta content="always" name="referrer">\n <meta name="theme-color" content="#2932e1">\n <link rel="s
hortcut icon" href="/favicon.ico" type="image/x-icon" />\n <link rel="search" type="application/opensearchdescription
+xml" href="/content-search.xml" title="\xe7\x99\xbe\xe5\xba\xa6\xe6\x90\x9c\xe7\xb4\xa2" />\n <link rel="icon" sizes
="any" mask href="//www.baidu.com/img/baidu_85beaf5496f291521eb75ba38eacbd87.svg">\n\t\n\t\n\t<link rel="dns-prefetch" h
ref="//s1.bdstatic.com"/>\n\t<link rel="dns-prefetch" href="//t1.baidu.com"/>\n\t<link rel="dns-prefetch" href="//t2.bai
du.com"/>\n\t<link rel="dns-prefetch" href="//t3.baidu.com"/>\n\t<link rel="dns-prefetch" href="//t10.baidu.com"/>\n\t<l
ink rel="dns-prefetch" href="//t11.baidu.com"/>\n\t<link rel="dns-prefetch" href="//t12.baidu.com"/>\n\t<link rel="dns-p
...省略
to_empty=!0,window.__switch_add_mask=!0;var s="http://s1.bdstatic.com/r/www/cache/static/global/js/all_async_search_eef4
222.js",n="/script";document.write("<script src=\'"+s+"\'><"+n+">"),bds.comm.newindex&&$(window).on("index_off",function
(){$(\'<div class="c-tips-container" id="c-tips-container"></div>\').insertAfter("#wrapper"),window.__sample_dynamic_tab
&&$("#s_tab").remove()\n}),bds.comm&&bds.comm.ishome&&Cookie.get("H_PS_PSSID")&&(bds.comm.indexSid=Cookie.get("H_PS_PSSI
D"))}();</script>\r\n\r\n\r\n\r\n<script>\r\nif(bds.comm.supportis){\r\n window.__restart_confirm_timeout=true;\r\n
window.__confirm_timeout=8000;\r\n window.__disable_is_guide=true;\r\n window.__disable_swap_to_empty=true;\r\n}
\r\ninitPreload({\r\n \'isui\':true,\r\n \'index_form\':"#form",\r\n \'index_kw\':"#kw",\r\n \'result_form\'
:"#form",\r\n \'result_kw\':"#kw"\r\n});\r\n</script>\r\n\r\n<script>\r\nif(navigator.cookieEnabled){\r\n\tdocument.c
ookie="NOJS=;expires=Sat, 01 Jan 2000 00:00:00 GMT";\r\n}\r\n</script>\r\n\r\n\n\n</body>\n</html>\n\r\n\r\n\r\n\n\r\n'
>>>
url拼接截图
6、info_collection注释
#_*_coding:utf-8_*_
from plugins import plugin_api
import json,platform,sys
class InfoCollection(object):
'''手机信息'''
def __init__(self):
pass
def get_platform(self):
os_platform = platform.system()
'''
获取平台是linux还是window
>>> import platform
>>> platform.system()
'Windows'
>>>
[root@adminset ~]# python
Python 2.7.5 (default, Apr 11 2018, 07:36:10)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> platform.system()
'Linux'
>>>
'''
return os_platform
def collect(self):
os_platform = self.get_platform()
'''
通过类反射看有没有相应的平台
'''
try:
func = getattr(self,os_platform)
info_data = func()
'''
获取的数据返回给collect平台了
'''
formatted_data = self.build_report_data(info_data)
return formatted_data
except AttributeError as e:
sys.exit("Error:MadKing doens't support os [%s]! " % os_platform)
def Linux(self):
sys_info = plugin_api.LinuxSysInfo()
return sys_info
def Windows(self):
sys_info = plugin_api.WindowsSysInfo()
print(sys_info)
#f = file('data_tmp.txt','wb')
#f.write(json.dumps(sys_info))
#f.close()
return sys_info
def build_report_data(self,data):
#add token info in here before send
return data
7、api_token注释
#_*_coding:utf-8_*_
import hashlib,time
def get_token(username,token_id):
timestamp = int(time.time())
md5_format_str = "%s\n%s\n%s" %(username,timestamp,token_id)
obj = hashlib.md5()
obj.update(md5_format_str)
print "token format:[%s]" % md5_format_str
print "token :[%s]" % obj.hexdigest()
return obj.hexdigest()[10:17], timestamp
if __name__ =='__main__':
print get_token('alex','test')
8、settings注释
#_*_coding:utf8_*_
import os
BaseDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
Params = {
"server": "192.168.1.38",
"port":9000,
'request_timeout':30,
"urls":{
"asset_report_with_no_id":"/asset/report/asset_with_no_asset_id/", #新资产批准区
"asset_report":"/asset/report/",#正式资产表
},
'asset_id': '%s/var/.asset_id' % BaseDir,
'''
你从服务器拿到资产ID,你只能存到文件里,你不肯呢个在本地建一个数据库吧!
存到var下,为什么是一个隐藏文件?
liunx的所有的进程号存在文件里,而且是隐藏的,所以我也存文件
'''
'log_file': '%s/logs/run_log' % BaseDir,
'auth':{
'user':'lijie3721@126.com',
'token': 'abc'
},
}
9、plugin_api注释
#_*_coding:utf-8_*_
from linux import sysinfo
def LinuxSysInfo():
#print __file__
return sysinfo.collect()
def WindowsSysInfo():
from windows import sysinfo as win_sysinfo
return win_sysinfo.collect()
'''
window的导入模块为什么写在下面,,这个是需要单独安装,
因为写在文件头,安装Linux的时候没有这个包会报错
'''
10、sysinfo注释
#_*_coding:utf-8_*_
__author__ = 'Alex Li'
import platform
import win32com
import wmi
import os
def collect():
data = {
'os_type': platform.system(),
'os_release':"%s %s %s "%( platform.release() ,platform.architecture()[0],platform.version()),
'os_distribution': 'Microsoft',
'asset_type':'server'
}
#data.update(cpuinfo())
win32obj = Win32Info()
data.update(win32obj.get_cpu_info())
data.update(win32obj.get_ram_info())
data.update(win32obj.get_server_info())
data.update(win32obj.get_disk_info())
data.update(win32obj.get_nic_info())
#for k,v in data.items():
# print k,v
return data
class Win32Info(object):
def __init__(self):
self.wmi_obj = wmi.WMI()
self.wmi_service_obj = win32com.client.Dispatch("WbemScripting.SWbemLocator")
self.wmi_service_connector =self.wmi_service_obj.ConnectServer(".","root\cimv2")
def get_cpu_info(self):
data = {}
cpu_lists = self.wmi_obj.Win32_Processor()
cpu_core_count = 0
for cpu in cpu_lists:
cpu_core_count += cpu.NumberOfCores
cpu_model = cpu.Name
data["cpu_count"] = len(cpu_lists)
data["cpu_model"] = cpu_model
data["cpu_core_count"] =cpu_core_count
return data
def get_ram_info(self):
data = []
ram_collections = self.wmi_service_connector.ExecQuery("Select * from Win32_PhysicalMemory")
for item in ram_collections:
item_data = {}
#print item
mb = int(1024 * 1024)
ram_size = int(item.Capacity) / mb
item_data = {
"slot":item.DeviceLocator.strip(),
"capacity":ram_size,
"model":item.Caption,
"manufactory":item.Manufacturer,
"sn":item.SerialNumber,
}
data.append(item_data)
#for i in data:
# print i
return {"ram":data}
def get_server_info(self):
computer_info = self.wmi_obj.Win32_ComputerSystem()[0]
system_info = self.wmi_obj.Win32_OperatingSystem()[0]
data = {}
data['manufactory'] = computer_info.Manufacturer
data['model'] = computer_info.Model
data['wake_up_type'] = computer_info.WakeUpType
data['sn'] = system_info.SerialNumber
#print data
return data
def get_disk_info(self):
data = []
for disk in self.wmi_obj.Win32_DiskDrive():
#print disk.Model,disk.Size,disk.DeviceID,disk.Name,disk.Index,disk.SerialNumber,disk.SystemName,disk.Description
item_data = {}
iface_choices = ["SAS","SCSI","SATA","SSD"]
for iface in iface_choices:
if iface in disk.Model:
item_data['iface_type'] = iface
break
else:
item_data['iface_type'] = 'unknown'
item_data['slot'] = disk.Index
item_data['sn'] = disk.SerialNumber
item_data['model'] = disk.Model
item_data['manufactory'] = disk.Manufacturer
item_data['capacity'] = int(disk.Size ) / (1024*1024*1024)
data.append(item_data)
return {'physical_disk_driver':data}
def get_nic_info(self):
data = []
for nic in self.wmi_obj.Win32_NetworkAdapterConfiguration():
if nic.MACAddress is not None:
item_data = {}
item_data['macaddress'] = nic.MACAddress
item_data['model'] = nic.Caption
item_data['name'] = nic.Index
if nic.IPAddress is not None:
item_data['ipaddress'] = nic.IPAddress[0]
item_data['netmask'] = nic.IPSubnet
else:
item_data['ipaddress'] = ''
item_data['netmask'] = ''
bonding = 0
#print nic.MACAddress ,nic.IPAddress,nic.ServiceName,nic.Caption,nic.IPSubnet
#print item_data
data.append(item_data)
return {'nic':data}
if __name__=="__main__":
collect()
获取cpu信息
PS Y:\MadkingClient> python
Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> import win32com
>>> import wmi
>>> import os
>>> wmi_obj = wmi.WMI()
>>> wmi_service_obj = win32com.client.Dispatch("WbemScripting.SWbemLocator")
>>> wmi_service_connector = wmi_service_obj.ConnectServer(".","root\cimv2")
>>> wmi_obj.Win32_Processor()
[<_wmi_object: b'\\\\XK104\\root\\cimv2:Win32_Processor.DeviceID="CPU0"'>]
>>> cpu_list = wmi_obj.Win32_Processor()
>>> dir(cpu_list[0])
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getat
tribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__re
duce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_associated_classes'
, '_cached_associated_classes', '_cached_methods', '_cached_properties', '_getAttributeNames', '_get_keys', '_instance_o
f', '_keys', '_methods', '_properties', 'associated_classes', 'associators', 'derivation', 'id', 'keys', 'methods', 'ole
_object', 'path', 'properties', 'property_map', 'put', 'qualifiers', 'references', 'set', 'wmi_property']
>>> cpu = cpu_list[0]
>>> cpu.id
'winmgmts:{authenticationlevel=pktprivacy,impersonationlevel=impersonate}!\\\\xk104\\root\\cimv2:win32_processor.devicei
d="cpu0"'
>>> cpu.Name
'Intel(R) Core(TM) i5-4570 CPU @ 3.20GHz'
>>> cpu.NumberOfCores
4
获取内存信息
PS C:\Users\Administrator> python
Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import platform
>>> import win32com
>>> import wmi
>>> import os
>>> wmi_service_obj = win32com.client.Dispatch("WbemScripting.SWbemLocator")
>>> wmi_service_connector = wmi_service_obj.ConnectServer(".","root\cimv2")
>>> ram_collections = wmi_service_connector.ExecQuery("Select * from Win32_PhysicalMemory")
>>> ram_collections
<COMObject <unknown>>
>>> for i in ram_collections:
... print(i.Capacity,i.Caption,i.Manufacturer,i.SerialNumber,i.DeviceLocator)
...
8589934592 Physical Memory Kingston 16474864 ChannelB-DIMM1
>>>
遇到的坑:
1、Python中expected an indented block 缩进的问题
2、Manufacturer单词写错
收集资产截图
11、新资产待审批区表结构注释
class NewAssetApprovalZone(models.Model):
"""新资产待审批区"""
sn = models.CharField(u'资产SN号', max_length=128, unique=True)
asset_type_choices = (
('server', u'服务器'),
('switch', u'交换机'),
('router', u'路由器'),
('firewall', u'防火墙'),
('storage', u'存储设备'),
('NLB', u'NetScaler'),
('wireless', u'无线AP'),
('software', u'软件资产'),
('others', u'其它类'),
)
asset_type = models.CharField(choices=asset_type_choices, max_length=64, blank=True, null=True)
manufactory = models.CharField(max_length=64, blank=True, null=True)
model = models.CharField(max_length=128, blank=True, null=True)
ram_size = models.IntegerField(blank=True, null=True)
cpu_model = models.CharField(max_length=128, blank=True, null=True)
cpu_count = models.IntegerField(blank=True, null=True)
cpu_core_count = models.IntegerField(blank=True, null=True)
os_distribution = models.CharField(max_length=64, blank=True, null=True)
os_type = models.CharField(max_length=64, blank=True, null=True)
os_release = models.CharField(max_length=64, blank=True, null=True)
"""
客户端过来的数据会临时存到临时表里
上面的字段都不重要,重要的就是下面的data,data里面会存上面?存所有的资产信息
"""
data = models.TextField(u'资产数据')
date = models.DateTimeField(u'汇报日期', auto_now_add=True)
approved = models.BooleanField(u'已批准', default=False)
approved_by = models.ForeignKey('UserProfile', verbose_name=u'批准人', blank=True, null=True)
approved_date = models.DateTimeField(u'批准日期', blank=True, null=True)
def __str__(self):
return self.sn
class Meta:
verbose_name = '新上线待批准资产'
verbose_name_plural = "新上线待批准资产"
来源:oschina
链接:https://my.oschina.net/u/4404140/blog/3928798