0
点赞
收藏
分享

微信扫一扫

14.服务器资源1,表级验证,字段验证,关联字段等

追风骚年 2022-04-14 阅读 118
django

模型层
在这里插入图片描述

逻辑处理(自动处理)

  1. 采集的数据中的产品型号如果产品型号表中没有,则新建
  2. 采集的数据中的供应商如果网供应商表没有,则新建
  3. 采集的数据中的网卡设备和IP如果在网卡设备表和IP表中没有,则新建
    这几个字段不允许通过接口进行,在接口层是只读

其他字段可以手动维护

模板层

from enum import unique
from ipaddress import ip_address
from django.db import models
from manufacturer.models import Manufacturer,ProductModel
from idcs.models import Idc
from cabinet.models import Cabinet
class Server(models.Model):
    #ssh 登录的IP
    ip = models.CharField("管理IP",max_length=15,db_index=True,unique=True,help_text="管理IP")
    hostname = models.CharField("主机名",max_length=20,db_index=True,unique=True,help_text="主机名")
    cpu = models.CharField("CPU",max_length=50,help_text="CPU")
    mem= models.CharField("内存",max_length=32,help_text="内存")
    disk= models.CharField("磁盘",max_length=200,help_text="磁盘")
    os= models.CharField("操作系统",max_length=50,help_text="操作系统")
    sn= models.CharField("SN",max_length=50,db_index=True,help_text="SN")
    manufacturer= models.ForeignKey(Manufacturer,on_delete=models.CASCADE,verbose_name="制造商",help_text="制造商")
    model_name= models.ForeignKey(ProductModel,on_delete=models.CASCADE,verbose_name="服务器型号",help_text="服务器型号")
    rmt_card_ip= models.CharField("管理卡IP",max_length=15,db_index=True,help_text="管理卡IP")
    idc= models.ForeignKey(Idc,on_delete=models.SET_NULL,null=True,verbose_name="所在机房",help_text="所在机房")
    cabinet= models.ForeignKey(Cabinet,null=True,on_delete=models.SET_NULL,verbose_name="所在机柜",help_text="所在机柜")
    cabinet_position = models.CharField("机柜位置",max_length=20,help_text="机柜位置")
    uuid= models.CharField("UUID",max_length=50,db_index=True,unique=True,help_text="虚拟机唯一标识")
    last_check = models.DateTimeField("检测时间",db_index=True,auto_now=True,help_text="检测时间")
    remark = models.CharField("备注",max_length=200,null=True,help_text="备注")

    
    def __str__(self):
        return self.ip
    
    class Meta():
        db_table="resources_server"
        ordering = ["id"]
        
        
        
class NetworkDevice(models.Model):
    """
    网卡设备
    """
    name = models.CharField("网卡设备名",max_length=20,help_text="网卡设备名")
    mac_address = models.CharField("MAC地址",max_length=32,help_text="MAC地址")
    host = models.ForeignKey(Server,on_delete=models.CASCADE,verbose_name="所在服务器",help_text="所在服务器")
    remark = models.CharField("备注",max_length=200,null=True,help_text="备注")
    
    def __self__(self):
        return self.name
    
    class Meta:
        db_table="resources_network_device"
        ordering=["id"]
        
class IP(models.Model):
    """
    IP模型
    """
    ip_addr = models.CharField("IP地址",max_length=15,db_index=True,unique=True,help_text="IP地址")
    netmask = models.CharField("子网掩码",max_length=15,help_text="子网掩码")
    remark = models.CharField("备注",max_length=200,null=True,help_text="备注")
    device= models.ForeignKey(NetworkDevice,on_delete=models.CASCADE,verbose_name="所在网卡",help_text="所在网卡")
    
    def __str__(self):
        return self.ip_addr
    
    class Meta:
        db_table = "resources_ip"
        ordering = ["id"]

视图层

from .models import Server,NetworkDevice,IP
from .serializers import  ServerAutoReportSerializer,NetworkDeviceSerializer,IPSerializer,ServerSerializer
from rest_framework import viewsets,mixins


from django_filters.rest_framework import DjangoFilterBackend
#from .filters import ServerFilter
# 这个视图名称添加Auto,表示它是自动收集服务器数据,并且是自动收集,所以只支持post上传<mixins.CreateModelMixin>
# 当前示例是服务器的信息资源发生变更,则会自动变更
class ServerAutoReportViewSet(mixins.CreateModelMixin,viewsets.GenericViewSet):
    """
    create:
        创建一个服务器
    """
    queryset = Server.objects.all()
    serializer_class = ServerAutoReportSerializer

class ServerViewSet(viewsets.ReadOnlyModelViewSet):
    """
    retrieve:
        读取一个服务器信息
    List:
        列出所有服务器信息
    """
    queryset = Server.objects.all()
    serializer_class = ServerSerializer
    

# 对于网络设备都是自动处理,所以设置为只读
class NetworkDeviceViewSet(viewsets.ReadOnlyModelViewSet):
    """
    retrieve:
        返回指定网卡信息
    List:
        返回网卡列表
    """
    queryset = NetworkDevice.objects.all()
    serializer_class = NetworkDeviceSerializer
# 对于IP都是自动处理,所以设置为只读
class IPViewSet(viewsets.ReadOnlyModelViewSet):
    """
    retrieve:
        返回指定ip信息
    List:
        返回ip列表
    """
    queryset = IP.objects.all()
    serializer_class = IPSerializer

序列化

from rest_framework import serializers
from servers.models import Server,NetworkDevice,IP
from manufacturer.models import ProductModel,Manufacturer

class ServerAutoReportSerializer(serializers.Serializer):
    """
    服务器同步序列化,这相当于是第一步检查,在这一步不做外键检查。
    manufacturer = serializers.PrimaryKeyRelatedField(many=False,queryset=Manufacturer.objects.all())
    """
    ip              = serializers.IPAddressField(required=True)
    hostname        = serializers.CharField(required=True, max_length=20)
    cpu             = serializers.CharField(required=True, max_length=50)
    mem             = serializers.CharField(required=True, max_length=20)
    disk            = serializers.CharField(required=True, max_length=200)
    os              = serializers.CharField(required=True, max_length=50)
    sn              = serializers.CharField(required=True, max_length=50)  
    manufacturer    = serializers.CharField(required=True)
    model_name      = serializers.CharField(required=True)
    uuid            = serializers.CharField(required=True, max_length=50)
    #网卡和ip模型,server表中没有这个,它是一个关联对象
    network         = serializers.JSONField(required=True)
    
    
    ''''
    一、先处理制造商,因为它自身没有任何关联关系,两种情况
    1.它存在,只需要拿到它,返回供应商的instance
    2.不存在,则需要创建,单独定义方法创建它
    总之,这个validate_manufacturer方法,在返回的时候一定要有 Manufacturer实例
    '''
    def validate_manufacturer(self, value):
        try:
            return Manufacturer.objects.get(vendor_name__exact=value)
        # 如果Manufacturer则创建它
        except Manufacturer.DoesNotExist:
            return self.create_manufacturer(value)
    

    def create_manufacturer(self,vendor_name):
        return Manufacturer.objects.create(vendor_name=vendor_name)

    
    
    '''
    二、服务器型号
    验证完制造商后,处理服务器型号,它只能在对象(表)级别验证的时候操作。
    首先拿到制造商的instacne,因为型号和制造商是多对一关系。 
    这个attr存储的是server的所有数据,是个键值对。manufacturer_obj = attrs['manufacturer']  它可以得到对应制造商的instance
    拿到一个制造商的对象后,需要检查有没有这个型号。如果制造商没有这个型号,则创建
    如果何种情况,一定要将这个型号转换成对应型号的实例,然后返回
    
    '''
    
    def validate(self, attrs):
        # network = attrs["network"]  
        # del attrs["network"] # 在处理字段的时候,处理完成要删除它,后续create保存的时候,会检查字段是否匹配
        manufacturer_obj = attrs['manufacturer']
        try:
            # 在制造商实例对应的产品模型中查找是否有这个型号的模型
            attrs['model_name'] = manufacturer_obj.productmodel_set.get(model_name__exact=attrs['model_name'])
        #在供应商下面的产品型号中查找是否有这个型号。如果存在返回,不存在报异常,就会去创建。它需要提供制造商的实例。
        except ProductModel.DoesNotExist:
            # 如果没有就创建这个模型,包含模型名称和制造商
            attrs['model_name'] = self.create_product_model(manufacturer_obj, attrs["model_name"])
        return attrs
    
    # 验证完成后,就可以创建模型
    def create_product_model(self,manufacturer_obj,model_name):
        return ProductModel.objects.create(model_name=model_name,vendor_name=manufacturer_obj)      
    

    '''
    额外知识:
    字典 pop() 方法删除字典给定键 key 及对应的值,返回值为被删除的值。key 值必须给出。 否则,返回 default 值。
    site= {'name': '菜鸟教程', 'alexa': 10000, 'url': 'www.runoob.com'}
    pop_obj=site.pop('name')
    print pop_obj    # 输出 :菜鸟教程
    '''
    
    
    '''
    三、生成server
    字段级别验证和对象(表)基表验证完成后。因为是post提交,所以是create
    因为当前这张表没有network这个字段。所以插入数据到表的时候,需要先将这个字段拿出来(也从原有的字典中剔除)。 再生成服务器的instance。
    注意:网卡的检查,需要先有servers的实例,才能检查。因为它和服务器的关系是n:1,是有关联关系的。

    '''
    
    def create(self,validated_data):
        # pop就是删掉network,对字典的操作.返回值就是个被删除的值. 因为Server没有这个字段,所以需要剔除处理
        # 移除数据库模型中不存在的属性
        network= validated_data.pop("network") 
        # 内部调用django模型类的save()方法
        server_obj = Server.objects.create(**validated_data) # 创建server 记录
        #server_obj.networkdevice_set = network_queryset # 设置它当中的一个集合等于列表。做一对多的关系
        # 需要先做判断,再关联。 因为网卡里有
        self.check_server_network_device(server_obj,network)
        return validated_data
    
    
    '''
    四、处理网卡
    '''
    def check_server_network_device(self, server_obj, network):

        '''
        # 当前服务器所有网卡
        这个网卡设备是否存在,它需要根据服务器来进行判断。
        先拿到当前服务器所有网卡,然后一条一条处理。来比对网卡设备表当中是否有当前服务器的网卡。
        如果不存在,则创建。 创建的时候需要注意它必须要关联上是哪台服务器。所以必须要提供server的instance
        '''
        network_device_queryset = server_obj.networkdevice_set.all()
        for device in network:
            try:
                # 检测device是否存在,如果不存在抛出异常
                network_device_queryset.get(name__exact=device['name'])

            except NetworkDevice.DoesNotExist:
                # device不存在
                self.create_network_device(server_obj, device)

    def create_network_device(self, server_obj, device):
        # 网卡设备当中没有ip字段,需要pop,device才能保存
        ips = device.pop('ips')
        # 这个device[“host”] 这个host是个外键,需要指定server的instance。 
        device['host'] = server_obj
        # 创建设备
        device_device_obj = NetworkDevice.objects.create(**device)
        # 继续处理网卡对应的IP 
        self.check_ip(device_device_obj, ips)
        return device_device_obj
    
    '''
    五、处理IP
    接下来处理IP 
    检查IP的时候,必须要知道这个IP是在哪块网卡设备上。
    检查ip是根据这个IP是在哪块网卡上。 
    先拿到所有网卡上的所有IP,进行匹配。如果存在不做任何操作。
    如果不存在,则创建这些IP 到对应网卡上。
    '''
 
    def check_ip(self, network_device_obj, ifnets):
        ip_queryset= network_device_obj.ip_set.all() 
        # 这个ifnet是当前所有网卡的IP
        for ifnet in ifnets: 
            try:
                # 如果不存在则创建
                ip_queryset.get(ip_addr__exact=ifnet['ip_addr']) 
            except IP.DoesNotExist:
                self.create_ip(network_device_obj, ifnet)
    
    # 创建这些IP 到对应网卡上。
    def create_ip(self, network_device_obj, ifnet):
        ifnet['device'] = network_device_obj
        return IP.objects.create(**ifnet)    
    

        
class ServerSerializer(serializers.ModelSerializer):
    """
    服务器序列化类
    """
    class Meta:
        model=Server
        fields="__all__"   
        

class IPSerializer(serializers.ModelSerializer):
    """
    服务器同步序列化类
    """
    class Meta:
        model=IP
        fields="__all__"        

class NetworkDeviceSerializer(serializers.ModelSerializer):
    """
    服务器同步序列化类
    """
    class Meta:
        model=NetworkDevice
        fields="__all__"  

路由及设置

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'idcs.apps.IdcsConfig',
    'users.apps.UsersConfig',
    'cabinet.apps.CabinetConfig',
    'manufacturer.apps.ManufacturerConfig',
    'servers.apps.ServersConfig',
]
# 导入子模块的视图
from idcs.views import IdcViewSet
from users.views import UserViewSet
from cabinet.views import CabinetViewSet
from manufacturer.views import ManufacturerViewSet,ProductModelViewSet
from servers.views import ServerAutoReportViewSet,NetworkDeviceViewSet,IPViewSet,ServerViewSet

# 注册
route = DefaultRouter()
route.register("idcs",IdcViewSet,basename="idcs")
route.register("users",UserViewSet,basename="users")
route.register("cabinet",CabinetViewSet,basename="cabinet")
route.register("manufacturer",ManufacturerViewSet,basename="manufacturer")
route.register("ProductModel",ProductModelViewSet,basename="ProductModel")
route.register("ServerAutoReport",ServerAutoReportViewSet,basename="ServerAutoReport")
route.register("NetworkDevice",NetworkDeviceViewSet,basename="NetworkDevice")
route.register("Server",ServerViewSet,basename="Server")
route.register("IP",IPViewSet,basename="IP")
举报

相关推荐

0 条评论