十6、cmdb的增删改查

初步实现cmdb增删改查功能,先实现功能后面补充样式。html

一、设计表,在models中定义好字段;

针对云主机:前端

硬件类型,     -->   服务器,交换机
环境,        -->    测试,上线,灰度 等到
运行的应用,   -->    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()),
]

三、利用Form表单来在前端展示数据:

这里咱们建立一个跟应用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')

四、咱们在apiAPP里面的viwe.py里面写增删改查逻辑

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')

五、编写tempates中的html,用于前端展现,

其中咱们须要一个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>

效果:
在这里插入图片描述 页码显示很差看不要紧,之后能够经过前端控制。