初步实现cmdb增删改查功能,先实现功能后面补充样式。html
针对云主机:前端
硬件类型, --> 服务器,交换机 环境, --> 测试,上线,灰度 等到 运行的应用, --> nginx, apache,docker, 等等 来源, --> 阿里云,腾讯云,物理机 上线状态, --> 上线,关机, 下线,待机 内网IP, --> 内网IP 外网IP, --> 外网IP 主机名, --> hostname 内存, --> memcache CPU, --> CPUINFO 硬盘, --> DISKS 内核, --> 内核版本 操做系统, --> OS:centos,Redhat,Debian, ecs_name, --> 云主机的标识 标识名, --> 标识名 区域/城市, --> 华南,华北,东北 等 机房/机柜 --> 机房/机柜 属性
定义:models.pypython
class Host(models.Model): # 最基础的主机表 '''主机,阿里云eth0 内网网卡, eth1 公网网卡''' hostname = models.CharField(max_length=64, blank=True, null=True, verbose_name='主机名') ecsname = models.CharField(max_length=64, blank=True, null=True, verbose_name='实例名') login_port = models.CharField(max_length=16, default='22', blank=True, null=True, verbose_name='登陆端口') cpu = models.CharField(max_length=8, blank=True, null=True, verbose_name='CPU') mem = models.CharField(max_length=8, blank=True, null=True, verbose_name='内存') speed = models.CharField(max_length=8, blank=True, default='5', null=True, verbose_name='带宽') eth1_network = models.CharField(max_length=32, blank=True, null=True, verbose_name='公网IP') eth0_network = models.CharField(max_length=32, verbose_name='私网IP') sn = models.CharField(max_length=64, blank=True, null=True, verbose_name='SN') kernel = models.CharField(max_length=64, blank=True, null=True, verbose_name='内核版本') # 内核+版本号 remarks = models.CharField(max_length=2048, blank=True, null=True, verbose_name='备注') createtime = models.CharField(max_length=32, blank=True, null=True, verbose_name='建立时间') expirytime = models.CharField(max_length=32, blank=True, null=True, verbose_name='到期时间') #ForeignKey #lab = models.ForeignKey(to='Lable',default=1,blank=True, null=True, verbose_name='标签') # os = models.ForeignKey(to='Os',default=1,blank=True, null=True, verbose_name='操做系统') # os+版本号 # the_upper = models.ForeignKey(to='Host', blank=True, null=True, verbose_name='宿主机', related_name='upper') source = models.ForeignKey(to='Source',default=1,blank=True, null=True, verbose_name='来源IP') # ManyToManyField logining = models.ManyToManyField(to='Login',default=1, verbose_name='所属用户') disks = models.ManyToManyField(to='Disk',default=1, verbose_name='磁盘') #这个字段只运行再内存里。这些信息不占磁盘的信息。 state_choices = ( (1, 'Running'), (2, '下线'), (3, '关机'), (4, '删除'), (5, '故障'), ) state = models.SmallIntegerField(verbose_name='主机状态', choices=state_choices, blank=True, null=True, ) def __str__(self): return self.hostname class Meta: verbose_name_plural = "主机表" class Login(models.Model): '''登陆相关''' login_name = models.CharField(max_length=16, default='root', verbose_name='登陆用户名') login_pwd= models.CharField(max_length=64, blank=True, null=True, verbose_name='登陆密码') auth=models.CharField(max_length=8,blank=True, null=True, verbose_name='具备权限') def __str__(self): return self.login_name class Meta: verbose_name_plural = "主机用户表" class Source(models.Model): '''来源:阿里云、物理机(某机房等)''' name = models.CharField(max_length=16, blank=True, null=True, verbose_name='来源') def __str__(self): return self.name class Meta: verbose_name_plural = "主机来源表"
初始化表,让其在数据库中建立对应的表:nginx
python manage.py makemigrations python manage.py migrate
这里咱们让增删改查走一个app,因此使用include引入:web
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^api/', include('apiAPP.urls')), ]
新建一个apiAPP,而后新建一个urls.py,咱们将其子路由定义在此。docker
from django.conf.urls import url,include from django.contrib import admin from apiAPP import views '''任何usl都会从这里匹配''' '''此处是精确匹配,写list.html,浏览器也要写list.html,后面带/的话,浏览器也要带/''' urlpatterns = [ url(r'^list\$', views.List.as_view()), url(r'^update/(\d+)/', views.Update.as_view()), url(r'^add.html', views.Add.as_view()), url(r'^del', views.Del.as_view()), ]
这里咱们建立一个跟应用app同级的目录,utils,而且建立
form_class.py:数据库
#!/usr/bin/python # -*- coding:utf-8 -*- # @Time : 2019/1/16 14:33 # @Author : liaochao # @File : form_class.py from django.forms import Form from django.forms import fields from django.forms import widgets from apiAPP import models class HostForm(Form): hostname = fields.CharField( required=True, #error_messages={'required': '不能为空'}, widget=widgets.TextInput(attrs={'class': 'form-control'}) ) cpu = fields.IntegerField( required=True, #error_messages={'required': '不能为空'}, widget=widgets.TextInput(attrs={'class': 'form-control'}) ) mem = fields.IntegerField( required=True, #error_messages={'required': '不能为空'}, widget=widgets.TextInput(attrs={'class': 'form-control'}) ) speed = fields.CharField( required=True, #error_messages={'required': '不能为空'}, widget=widgets.TextInput(attrs={'class': 'form-control'}) ) eth0_network = fields.CharField( required=True, #error_messages={'required': '不能为空'}, widget=widgets.TextInput(attrs={'class': 'form-control'}) ) state = fields.CharField( required=True, widget = widgets.TextInput(attrs={'class': 'form-control'}), ) messages = "舒适提示,这里请填写正确的数字, (1, 'Running'),(2, '下线'), (3, '关机'),(4, '删除'), (5, '故障')," source_id = fields.ChoiceField( required=True, # values_list('id','name') 会让数据变成[(id,name),(id,name)] 这种格式 choices=[], #下拉框 widget=widgets.Select(attrs={'class': 'form-control'}), ) region_id = fields.ChoiceField( required=True, choices=[], widget=widgets.Select(attrs={'class': 'form-control'}) ) def __init__(self,*args,**kwargs): '每次都默认执行初始化,保证在数据库拿到的数据是最新的' super(HostForm,self).__init__(*args,**kwargs) # 先执行 父类的 __init__方法,也就是 View类的__init__方法 # values_list('id','name') 会让数据变成[(id,name),(id,name)] 这种格式 self.fields['source_id'].choices = models.Source.objects.values_list('id','name') self.fields['region_id'].choices=models.Region.objects.values_list('id','name')
from django.shortcuts import render,HttpResponse,redirect from apiAPP import models from django.views import View from django.forms import Form from django.forms import fields from django.forms import widgets from utils import form_class # Create your views here. class List(View): def post(self,request,*args,**kwargs): pass def get(self,request,*args,**kwargs): # return HttpResponse('List') host_list=models.Host.objects.all() return render(request,'host.html',locals()) class Add(View): '''基于form的增长''' def post(self,request,*args,**kwargs): form =form_class.HostForm(data=request.POST) if form.is_valid(): print(form.cleaned_data) models.Host.objects.create(**form.cleaned_data) print("正常提交") return redirect('/api/list') else: print(form.errors) return render(request,'add.html',locals()) def get(self,request,*args,**kwargs): form = form_class.HostForm() return render(request,'add.html',locals()) class Update(View): '''基于form的修改''' def post(self,request,pk): #request 后面的值 pk 是 url传入的值,相似于 ->url 里 host.id print("post--id-->", pk) #这里传入的就是ID 值 form = form_class.HostForm(data=request.POST) if form.is_valid(): print(form.cleaned_data) models.Host.objects.filter(id=pk).update(**form.cleaned_data) return redirect('/api/list') else: print(form.errors) return render(request,'edit.html',locals()) def get(self,request,pk): print ("get--id-->",pk) # # 拿到前端传过来的id # get_id = request.GET.get('id') obj = models.Host.objects.filter(id=pk).first() print(obj) form = form_class.HostForm( #这里能够渲染到前端的内容, initial={ # initial 固定写法!这里的值是直接渲染到前端的 'hostname':obj.hostname, 'cpu':obj.cpu, 'mem':obj.mem, 'speed':obj.speed, 'eth0_network':obj.eth0_network, 'source_id':obj.source_id, 'region_id':obj.region_id, 'state': obj.state, # 'get_state_display ':obj.get_state_display , } ) # return HttpResponse('update') return render(request,'edit.html',locals()) class Del(View): def post(self,request,*args,**kwargs): pass def get(self,request,*args,**kwargs): get_id = int(request.GET.get('id')) models.Host.objects.filter(id=get_id).delete() return redirect('/api/list')
其中咱们须要一个list展现的host.html,增长的add.html,编辑的edit.html。
host.html:apache
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>主机列表</title> </head> <body> <div> <a href="/api/add">添加</a> </div> <div class="container"> <table class="table table-bordered table-hover" id="table"> <thead> <tr> <th> </th> <th>主机名</th> <th>CPU</th> <th>内存/G</th> <th>带宽/M</th> <th>IP</th> <th>来源类型</th> <th>所属区域</th> <th>状态</th> <th>编辑</th> <th>删除</th> </tr> </thead> <tbody> {% for host in host_list %} <tr> <td>{{ host.id }}</td> <td>{{ host.hostname }}</td> <td>{{ host.cpu }}</td> <td>{{ host.mem }}</td> <td>{{ host.speed }}</td> <td>{{ host.eth0_network }}</td> <td>{{ host.source.name }}</td> <td>{{ host.region.name }}</td> <td>{{ host.get_state_display }}</td> <td><a href="/api/update/{{ host.id }}">编辑</a></td> <td><a href="/api/del?id={{ host.id }}">删除</a></td> </tr> {% endfor %} </tbody> </table> </div> </body> </html>
add.html:django
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>主机添加</title> </head> <body> <form class="form-horisontal templatemo-container templatemo-login-form-1 margin-bottom-30" method="post" novalidate role="form"> {% csrf_token %} <p id="hostname">主机名:{{ form.hostname }} {{form.errors.hostname.0 }}</p> <p id="cpu">cpu:{{ form.cpu }} {{ form.errors.cpu.0 }}</p> <p id="mem">内存:{{ form.mem }} {{ form.errors.mem.0 }}</p> <p id="speed">带宽:{{ form.speed }} {{ form.errors.speed.0 }}</p> <p id="state">状态:{{ form.state}} {{ form.errors.state.0 }} </p> <p>{{ form.messages }}</p> <p id="eth0_network">网卡ip:{{ form.eth0_network }} {{ form.errors.eth0_network }}</p> <p id="source.name">来源:{{ form.source_id }}</p> <p id="region.name">区域:{{ form.region_id }}</p> <input type="submit" value="提交"> </form> </body> </html>
edit.html: 经过上面update 类的initial 的内容传入template模板渲染出centos
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>数据编辑</title> </head> <body> <form class="form-horisontal templatemo-container templatemo-login-form-1 margin-bottom-30" method="post" novalidate role="form"> {% csrf_token %} <p id="hostname">主机名:{{ form.hostname }} {{form.errors.hostname.0 }}</p> <p id="cpu">cpu:{{ form.cpu }} {{ form.errors.cpu.0 }}</p> <p id="mem">内存:{{ form.mem }} {{ form.errors.mem.0 }}</p> <p id="speed">带宽:{{ form.speed }} {{ form.errors.speed.0 }}</p> <p id="state">状态:{{ form.state}} {{ form.errors.state.0 }} </p> <p>{{ form.messages }}</p> <p id="eth0_network">网卡ip:{{ form.eth0_network }} {{ form.errors.eth0_network }}</p> <p id="source.name">来源:{{ form.source_id }}</p> <p id="region.name">区域:{{ form.region_id }}</p> <input type="submit" value="提交"> </body> </html>
访问List页面:
http://127.0.0.1:8000/api/list
点击添加:http://127.0.0.1:8000/api/add
点击修改跟添加相似,只是会默认取到这行数据的id,而后把数据所有填充进去。
点击删除会删除选中数据。
修改List方法:
class List(View): def get(self,request,*args,**kwargs): host_list=models.Host.objects.all() #分页,表示一页显示三条数据 p = Paginator(host_list,3) get_page=int(request.GET.get('page',1)) try: host_list=p.page(get_page) except PageNotAnInteger: host_list=p.page(1) except EmptyPage: host_list=p.page(p.num_pages) return render(request,'host.html',locals()) def post(self,request,*args,**kwargs): pass
修改host.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>主机列表</title> </head> <body> <div> <a href="/api/add.html">添加</a> </div> <div class="container"> <table class="table table-bordered table-hover" id="table"> <thead> <tr> <th>主机id </th> <th>主机名</th> <th>CPU</th> <th>内存/G</th> <th>带宽/M</th> <th>IP</th> <th>来源类型</th> <th>所属区域</th> <th>状态</th> <th>编辑</th> <th>删除</th> </tr> </thead> <tbody> {% for host in host_list %} <tr> <td>{{ host.id }}</td> <td>{{ host.hostname }}</td> <td>{{ host.cpu }}</td> <td>{{ host.mem }}</td> <td>{{ host.speed }}</td> <td>{{ host.eth0_network }}</td> <td>{{ host.source.name }}</td> <td>{{ host.region.name }}</td> <td>{{ host.get_state_display }}</td> <td><a href="/api/update/{{ host.id }}">编辑</a></td> <td><a href="/api/del?id={{ host.id }}">删除</a></td> </tr> {% endfor %} </tbody> </table> </div> <div> <ul class="pagination" id="pager"> {% if host_list.has_previous %} <li class="previous"><a href="/api/list/?page={{ host_list.previous_page_number }}">上一页</a></li> {% else %} <li class="previous disabled"><a href="#">上一页</a></li> {% endif %} <!-- 遍历页数 --> {% for num in p.page_range %} {% if num == page %} <li class="item active"></a><a href="/api/list/?page={{ num }}">{{ num }}</a></li> {% else %} <li class="item"><a href="/api/list/?page={{ num }}">{{ num }}</a></li> {% endif %} {% endfor %} <!--若是有下一页就拿到下一页的地址--> {% if host_list.has_next %} <li class="next"><a href="/api/list/?page={{ host_list.next_page_number }}">下一页</a></li> {% else %} <li class="next disabled"><a href="#">下一页</a></li> {% endif %} </ul> </div> </body> </html>
效果:
页码显示很差看不要紧,之后能够经过前端控制。