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提交了什么? 为什么没有下拉框了 ...
随机推荐
- 2星|《重新定义物流》:形式像PPT,内容像公关稿
全书彩印,彩图大概占一半篇幅,感觉是把一些PPT配上点说明拼成了一本书.前后的彩图风格差异较大,大部分给我的感觉都是堆砌名词术语的官方宣传材料,少部分色调单一形式简单的图,像是作者们自己绘制的,反而能 ...
- const关键字到底该怎么用
原文地址:https://www.yanbinghu.com/2019/01/28/7442.html 前言 我们都知道使用const关键字限定一个变量为只读,但它是真正意义上的只读吗?实际中又该如何 ...
- Python开发【第二篇】运算符
"+" 加号 __author__ = 'Tang' a = 8 b = 9 c = a + b a = 8.0 b = 9 c = a + b print(c) # 17.0 a ...
- 2018/05/14 03:56:10 [error] 12959#0: *42285845507 client intended to send too large body: 1664288 bytes
Syntax: client_max_body_size size; Default: client_max_body_size 1m; Context: http, server, location ...
- Java 8 中为什么要引出default方法
(原) default方法是java 8中新引入进的,它充许接口中除了有抽象方法以外,还可以拥用具有实现体的方法,这一点跟jdk8之前的版本已经完全不一样了,为什么要这样做呢? 拿List接口举例,在 ...
- web框架开发-Django模型层(1)之ORM简介和单表操作
ORM简介 不需要使用pymysql的硬编码方式,在py文件中写sql语句,提供更简便,更上层的接口,数据迁移方便(有转换的引擎,方便迁移到不同的数据库平台)…(很多优点),缺点,因为多了转换环节,效 ...
- web框架开发-Django的Forms组件
校验字段功能 针对一个实例:用户注册. 模型:models.py class UserInfo(models.Model): name=models.CharField(max_length=32) ...
- IDEA远程调试监控端口
大家知道,线上环境定位问题不是那么简单的,如果有非常完善的日志以及监控系统是不必担心的,但是应对这些并不完善的场景下,IDEA提供了一种远程调试的功能,remote集成了可以远程调试的功能,只需要在你 ...
- C#自定义应用程序上下文对象+IOC自己实现依赖注入
以前的好多代码都丢失了,加上最近时间空一些,于是想起整理一下以前的个人半拉子项目,试试让它们重生.自从养成了架构师视觉 搭建框架之后,越来 越看不上以前搭的框架了.先撸个上下文对象加上实现依赖注入.由 ...
- codeforces#1136 C. Nastya Is Transposing Matrices(找规律)
题意:给出两个n*m的矩阵,每次操作可以让一个正方形矩阵行列交换.问,在无限次操作下,第一个矩阵能否变成第二个矩阵 分析:先把操作限定在2*2的矩阵中.这样对角线上的元素就可以随意交换.也就是说,如果 ...