CMDB资产管理系统开发【day25】:windows客户端开发
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 = "新上线待批准资产"
CMDB资产管理系统开发【day25】:windows客户端开发的更多相关文章
- Python之CMDB资产管理系统
最近正好在给公司做CMDB资产管理系统,现在做的也差不多了,现在回头吧思路整理下. CMDB介绍 CMDB --Configuration Management Database 配置管理数据库, C ...
- CMDB资产管理系统开发【day25】:表结构设计1
资产表 # _*_coding:utf-8_*_ __author__ = 'jieli' from assets.myauth import UserProfile from django.db i ...
- CMDB资产管理系统开发【day26】:CMDB上节回顾
一.上节知识点回顾 服务器设计了一个表结构 开发了一个客户端 二.后台创建缓存区表 客户端连接服务器,在服务器的下面看报错信息 因为URL都没有写,所以我找不到呀 1.在MadKing\url.py ...
- C#.NET 大型通用信息化系统集成快速开发平台 4.0 版本 - 多系统开发接口 - 苹果客户端开发接口
最近工作上需要,给苹果客户端开发接口,实现集中统一的用户管理,下面是接口调用参考. 1: 获取OpenId? http://127.0.0.1/GetOpenId.ashx?username=Admi ...
- CMDB资产管理系统开发【day25】:需求分析
本节内容 浅谈ITIL CMDB介绍 Django自定义用户认证 Restful 规范 资产管理功能开发 浅谈ITIL TIL即IT基础架构库(Information Technology Infra ...
- CMDB资产管理系统开发【day25】:表结构设计2
表结构设计1详细注释代码 # _*_coding:utf-8_*_ __author__ = 'luoahong' from assets.myauth import UserProfile from ...
- CMDB资产管理系统开发【day26】:linux客户端开发
客户端疑难点及获取流程 1.linux客户端支持2就可以,python3就是很麻烦 难道你要求所有的客户端都上pytho3吗? 现在从bin的入口进去 HouseStark.ArgvHandler(s ...
- CMDB资产管理系统开发【day25】:Django 自定义用户认证
官方文档:https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#substituting-a-custom-user-mode ...
- CMDB资产管理系统开发【day26】:数据正式存入待存区
1.from表单提交 1.数据提交到哪里呢? 提交到assets/new_assets_approval.html这了 2.Yes, I'm sure提交了什么? 为什么没有下拉框了 ...
随机推荐
- c/c++ 继承与多态 容器与继承1
问题:类B公有继承类A,类A有虚函数fun,类B覆盖了虚函数fun,有一个std::vector<A>,添加A的对象a,和B的对象b,到这个容器里,然后从vector里取出来,使用对象a. ...
- elasticsearch系列一:elasticsearch(ES简介、安装&配置、集成Ikanalyzer)
一.ES简介 1. ES是什么? Elasticsearch 是一个开源的搜索引擎,建立在全文搜索引擎库 Apache Lucene 基础之上 用 Java 编写的,它的内部使用 Lucene 做索引 ...
- IBM小练习
'''例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解) 成人的BMI数值: 过轻:低于18.5 正常:18.5-23.9 过重:24- ...
- Redis学习笔记(2)——Redis的下载安装部署
一.下载Redis Redis的官网下载页上有各种各样的版本,如图 但是官网下载的Redis项目不正式支持Windows.如果需要再windows系统上部署,要去GitHub上下载.我下载的是Redi ...
- HBase Client JAVA API
旧 的 HBase 接口逻辑与传统 JDBC 方式很不相同,新的接口与传统 JDBC 的逻辑更加相像,具有更加清晰的 Connection 管理方式. 同时,在旧的接口中,客户端何时将 Put 写到服 ...
- maven-assembly-plugin打包可执行的jar包
pom.xml添加 <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</a ...
- Vue 自定义一个插件的用法、小案例及在项目中的应用
1.开发插件 install有两个参数,第一个是Vue构造器,第二个参数是一个可选的选项对象 MyPlugin.install = function (Vue, options) { // 1 ...
- IDEA+Maven+各个分支代码进行合并
各个模块的分支代码进行合并到一起:https://blog.csdn.net/xsj_blog/article/details/79198502
- AI Conditional GAN
Conditional GAN 参考链接: https://arxiv.org/pdf/1611.07004v1.pdf
- python之shutil
''' shutil 用来处理 文件 文件夹 压缩包 的模块 ''' import shutil # 拷贝文件内容 shutil.copyfileobj(open('old.xml', 'r'), o ...