千家信息网

Django之入门 CMDB系统 (四) 增删改查

发表于:2024-09-22 作者:千家信息网编辑
千家信息网最后更新 2024年09月22日,Django之入门 CMDB系统 (四) 增删改查前言作者: 何全,github地址: https://github.com/hequan2017 QQ交流群: 620176501通过此教程完成从零入
千家信息网最后更新 2024年09月22日Django之入门 CMDB系统 (四) 增删改查

Django之入门 CMDB系统 (四) 增删改查


前言

作者: 何全,github地址: https://github.com/hequan2017 QQ交流群: 620176501

通过此教程完成从零入门,能够独立编写一个简单的CMDB系统。

目前主流的方法开发方式,分为2种:mvc 和 mvvc方式。本教程为 mvc 方式,即 django负责渲染html。后面会推出 mvvc(前后端分离)的入门教程。

教程项目地址: https://github.com/hequan2017/husky/

教程文档地址: https://github.com/hequan2017/husky/tree/master/doc

说明

  • cbv 在视图里使用类处理请求 (下面采用这种方式,比较会抽象一点,但是会比较简洁)
  • fbv 在视图里使用函数处理请求

基础设置

pycharm : 菜单栏 tools --> 选择 run manage.py task

manage.py@husky > startapp asset ##创建 asset app

具体内容请看实际页面,下面只是把重点代码 进行展示。

  • settings.py 增加系统配置
import sysINSTALLED_APPS = [    "asset",]
  • asset/modes.py
from django.db import modelsclass Ecs(models.Model):    TYPE_CHOICES = (        ('阿里云', '阿里云'),        ('腾讯云', '腾讯云'),        ('华为云', '华为云'),        ('亚马逊', '亚马逊'),        ('其他', '其他'),        (None,None),    )    hostname = models.CharField(max_length=96, verbose_name='主机名', blank=True, null=True, )    type = models.CharField(choices=TYPE_CHOICES, max_length=16, verbose_name='主机类型', blank=True, null=True, )    instance_id = models.CharField(max_length=64, verbose_name='实例ID', unique=True)    instance_name = models.CharField(max_length=96, verbose_name='标签', blank=True, null=True, )    os_name = models.CharField(max_length=64, verbose_name='系统版本', blank=True, null=True, )    cpu = models.IntegerField(verbose_name='CPU', blank=True, null=True)    memory = models.IntegerField(verbose_name='内存', blank=True, null=True)    private_ip = models.GenericIPAddressField(verbose_name='内网IP', blank=True, null=True)    public_ip = models.GenericIPAddressField(verbose_name='外网IP', blank=True, null=True)    c_time = models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间', blank=True)    u_time = models.DateTimeField(auto_now=True, null=True, verbose_name='更新时间', blank=True)    class Meta:        db_table = "ecs"        verbose_name = "主机"        verbose_name_plural = verbose_name    def __str__(self):        return self.hostname

pycharm : 菜单栏 tools --> 选择 run manage.py task

makemigrations 生成数据文件

migrate 根据文件,执行生成表结构

  • asset/form.py
from django import formsfrom asset.models import Ecsclass EcsForm(forms.ModelForm):    class Meta:        model = Ecs        fields = '__all__'        widgets = {            'type': forms.Select(                attrs={'class': 'select2',                       'data-placeholder': '----请选择环境----'}),        }        help_texts = {            'type': '* 请选择 资产所在平台.',        }    def clean_type(self):        """        自定义验证        :return:        """        type = self.cleaned_data['type']        return type
  • asset/admin.py
from django.contrib import adminfrom asset.models import Ecsadmin.site.register(Ecs)
  • 自定义标签处理
    • asset/templatetags/asset_filter.py
from django import templatefrom django.apps import appsfrom asset.models import Ecsregister = template.Library()@register.filter(name='ecs_model_choices')def ecs_model_choices(model_name, choice_name):    asset_app = apps.get_app_config('assets')    return getattr(asset_app.get_model(model_name), choice_name)@register.filter(name='ecs_type_choices')def ecs_type_choices(value):    return  Ecs.TYPE_CHOICES

增加

  • asset/views.py
class EcsCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):    """    Ecs 创建    """    permission_required = ('asset.add_ecs',)    model = Ecs    form_class = EcsForm    template_name = 'asset/ecs-create.html'    success_url = reverse_lazy('asset:ecs-list')    def get_context_data(self, **kwargs):        context = {}        if '__next__' in self.request.POST:  # 为了获取 点击本页之前的 浏览网页            context['i__next__'] = self.request.POST['__next__']        else:            try:                context['i__next__'] = self.request.META['HTTP_REFERER']            except Exception as e:                logger.error(e)        kwargs.update(context)        return super().get_context_data(**kwargs)    def get_success_url(self):        return self.request.POST['__next__']    def form_valid(self, form):  #  保存结果 可以进行 手动 修改 再保存        obj = form.save(commit=False)        obj.save()        return super().form_valid(form)    def form_invalid(self, form):        print(form.errors)        """If the form is invalid, render the invalid form."""        return self.render_to_response(self.get_context_data(form=form))
  • asset/urls.py
from django.urls import pathfrom asset import viewsapp_name = "asset"urlpatterns = [    path('ecs-create', views.EcsCreateView.as_view(), name='ecs-create')]
  • templates/base/_js.html
  • templates/base/_nav.html
                
  • templates/asset/ecs-create.html
    
{% csrf_token %} {% if form.non_field_errors %}
{{ form.non_field_errors }}
{% endif %}

基本

{% bootstrap_field form.hostname layout="horizontal" %} {% bootstrap_field form.type layout="horizontal" %} {% bootstrap_field form.instance_id layout="horizontal" %} {% bootstrap_field form.instance_name layout="horizontal" %} {% bootstrap_field form.os_name layout="horizontal" %} {% bootstrap_field form.cpu layout="horizontal" %} {% bootstrap_field form.memory layout="horizontal" %} {% bootstrap_field form.private_ip layout="horizontal" %} {% bootstrap_field form.public_ip layout="horizontal" %}
{% bootstrap_button "保存" button_type="submit" button_class="btn-primary" %} 取消
{% block footer-js %} {% endblock %}

列表

  • asset/views.py
def get_list(function):    """    列表页面  获取 搜索    :param function: self.model    :return:    """    @wraps(function)    def wrapped(self):        # user = self.request.user        # groups = [x['name'] for x in self.request.user.groups.values()]        # request_type = self.request.method        # model = str(self.model._meta).split(".")[1]        filter_dict = {}        not_list = ['page', 'order_by', 'csrfmiddlewaretoken']        for k, v in dict(self.request.GET).items():            if [i for i in v if i != ''] and (k not in not_list):                if '__in' in k:                    filter_dict[k] = v                else:                    filter_dict[k] = v[0]        self.filter_dict = filter_dict        self.queryset = self.model.objects.filter(**filter_dict).order_by('-id')        order_by_val = self.request.GET.get('order_by', '')        if order_by_val:            self.queryset = self.queryset.order_by(order_by_val) if self.queryset else self.queryset        result = function(self)        return result    return wrappedclass EcsListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):    permission_required = ('asset.view_ecs',)    template_name = 'asset/ecs-list.html'    model = Ecs    queryset = Ecs.objects.get_queryset().order_by('-id')    @get_list  ## 处理查询    def get_context_data(self, **kwargs):        try:            page = self.request.GET.get('page', 1)        except PageNotAnInteger as e:            page = 1        p = Paginator(self.queryset, getattr(settings, 'DISPLAY_PER_PAGE'), request=self.request)        ecs_list = p.page(page)        context = {            "ecs_list": ecs_list,            "filter_dict": self.filter_dict  # 把查询条件返回给前端        }        kwargs.update(context)        return super().get_context_data(**kwargs)
  • asset/urls.py
path('ecs-list', views.EcsListView.as_view(), name='ecs-list'),
  • templates.py/asset/ecs-list.html
   
{% csrf_token %} {% for row in ecs_list.object_list %} {% endfor %}
主机名 主机类型 实例ID 标签 系统版本 内网IP 创建时间 操作
{{ row.hostname }}
{{ row.get_type_display }}
{{ row.instance_id }}
{{ row.instance_name }}
{{ row.os_name }}
{{ row.private_ip }}
{{ row.c_time | date:'Y-m-d' }}
{% if perms.asset.view_ecs %} 详情 {% endif %} {% if perms.asset.change_ecs %} 编辑 {% endif %} {% if perms.asset.delete_ecs %} 删除 {% endif %}
{% block footer-js %}

更新

  • asset/views.py
class EcsUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):    permission_required = ('asset.change_ecs',)    model = Ecs    form_class = EcsForm    template_name = 'asset/ecs-create.html'    success_url = reverse_lazy('asset:ecs-list')    def get_context_data(self, **kwargs):        context = {}        if '__next__' in self.request.POST:  # 为了获取 点击本页之前的 浏览网页            context['i__next__'] = self.request.POST['__next__']        else:            try:                context['i__next__'] = self.request.META['HTTP_REFERER']            except Exception as e:                logger.error(e)        kwargs.update(context)        return super().get_context_data(**kwargs)    def get_success_url(self):        return self.request.POST['__next__']
  • asset/urls.py
    path('ecs-update-', views.EcsUpdateView.as_view(), name='ecs-update'),
  • templates.py/asset/ecs-create.html 创建页面 同时也当更新页面
     {% if perms.asset.change_ecs %}        编辑    {% endif %}

删除

  • asset/views.py
class EcsDeleteView(LoginRequiredMixin, PermissionRequiredMixin, View):    permission_required = ('asset.delete_ecs',)    model = Ecs    def post(self, request):        ret = {'status': True, 'error': None, }        nid = self.request.POST.get('nid', None)        self.model.objects.get(id=nid).delete()        return HttpResponse(json.dumps(ret))
  • asset/urls.py

path('ecs-delete', views.EcsDeleteView.as_view(), name='ecs-delete'),

templates.py/asset/ecs-list.html

 {% if perms.asset.delete_ecs %} 删除  {% endif %}
   $(function () {                $_(document).on('click', '.ecs-delete', function () {                    var id = $(this).parent().parent().attr('id');                    var name = $(this).parent().parent().attr('name');                    swal({                        title: "你确定删除",                        text: name,                        type: "warning",                        showCancelButton: true,                        confirmButtonColor: "#DD6B55",                        confirmButtonText: "确定",                        cancelButtonText: "取消",                        closeOnConfirm: false                    }, function () {                        $.ajax({                            url: "{% url 'asset:ecs-delete' %}",                            type: 'POST',                            data: {'nid': id},                            success: function (data) {                                var obj = JSON.parse(data);                                if (obj.status) {                                    swal({title: "删除", text: "已成功删除", type: "success"}, function () {                                        _window.location.reload();                                    })                                } else {                                    swal("错误", "删除" + "[ " + obj.error + " ]" + "遇到错误", "error");                                }                            }                        });                    });                });            });

详情

  • asset/views.py
class EcsDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):    permission_required = ('asset.view_ecs',)    model = Ecs    form_class = EcsForm    template_name = 'asset/ecs-detail.html'    def get_context_data(self, **kwargs):        pk = self.kwargs.get(self.pk_url_kwarg, None)        context = {            "ecs": self.model.objects.get(id=pk),            "nid": pk        }        kwargs.update(context)        return super().get_context_data(**kwargs)
  • asset/urls.py

path('ecs-detail-', views.EcsDetailView.as_view(), name='ecs-detail'),

  • templates.py/asset/ecs-list.html
    
主机类型: {{ ecs.get_type_display }}
实例ID: {{ ecs.instance_id }}
标签: {{ ecs.instance_name }}
系统版本: {{ ecs.os_name }}
CPU: {{ ecs.cpu }}
内存: {{ ecs.memory }}
内网IP: {{ ecs.private_ip }}
外网IP: {{ ecs.public_ip }}
创建时间: {{ ecs.c_time }}
更新时间: {{ ecs.u_time }}
0