Introduction to Django add, delete, modify and query in CMDB system

Introduction to Django CMDB system

Preface

Author: he Quan, github address: https://github.com/hequan2017 QQ communication group: 620176501

Through this tutorial, you can start from scratch and write a simple CMDB system independently.

At present, there are two main development methods: mvc and mvvc. This tutorial is in mvc mode, that is, django is responsible for rendering html. The introduction of mvvc (front and back separation) will be introduced later.

Tutorial project address: https://github.com/hequan2017/husky/

Tutorial document address: https://github.com/hequan2017/husky/tree/master/doc

Explain

  • cbv uses classes to process requests in views (in this way, it will be more abstract, but it will be simpler)
  • fbv uses functions to process requests in views

Foundation setup

pycharm: select run manage.py task from tools

Manage.py @ husky > startapp asset create asset app

Please refer to the actual page for details. The following is just the key code to show.

  • settings.py add system configuration
import sys
INSTALLED_APPS = [
    "asset",
]
  • asset/modes.py
from django.db import models

class Ecs(models.Model):
    TYPE_CHOICES = (
        ('Ali cloud', 'Ali cloud'),
        ('Tencent cloud', 'Tencent cloud'),
        ('Hua Wei Yun', 'Hua Wei Yun'),
        ('Amazon', 'Amazon'),
        ('Other', 'Other'),
        (None,None),
    )
    hostname = models.CharField(max_length=96, verbose_name='host name', blank=True, null=True, )
    type = models.CharField(choices=TYPE_CHOICES, max_length=16, verbose_name='Host type', blank=True, null=True, )
    instance_id = models.CharField(max_length=64, verbose_name='Example ID', unique=True)
    instance_name = models.CharField(max_length=96, verbose_name='Label', blank=True, null=True, )
    os_name = models.CharField(max_length=64, verbose_name='System version', blank=True, null=True, )
    cpu = models.IntegerField(verbose_name='CPU', blank=True, null=True)
    memory = models.IntegerField(verbose_name='Memory', blank=True, null=True)
    private_ip = models.GenericIPAddressField(verbose_name='Intranet IP', blank=True, null=True)
    public_ip = models.GenericIPAddressField(verbose_name='Extranet IP', blank=True, null=True)

    c_time = models.DateTimeField(auto_now_add=True, null=True, verbose_name='Creation time', blank=True)
    u_time = models.DateTimeField(auto_now=True, null=True, verbose_name='Update time', blank=True)

    class Meta:
        db_table = "ecs"
        verbose_name = "Host"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.hostname

pycharm: select run manage.py task from tools

makemigrations generate data files

migrate executes the generate table structure according to the file

  • asset/form.py
from django import forms
from asset.models import Ecs

class EcsForm(forms.ModelForm):
    class Meta:
        model = Ecs
        fields = '__all__'

        widgets = {
            'type': forms.Select(
                attrs={'class': 'select2',
                       'data-placeholder': '----Please select environment----'}),
        }

        help_texts = {
            'type': '* Please select the platform of the asset.',

        }

    def clean_type(self):
        """
        //Custom validation
        :return:
        """
        type = self.cleaned_data['type']
        return type
  • asset/admin.py
from django.contrib import admin
from asset.models import Ecs

admin.site.register(Ecs)
  • Custom label processing
    • asset/templatetags/asset_filter.py
from django import template
from django.apps import apps
from asset.models import Ecs
register = 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

increase

  • asset/views.py
class EcsCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
    """
    Ecs Establish
    """
    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:  # To get the browsing page before clicking this page
            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):  #  The saved result can be modified manually and then saved
        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 path
from asset import views

app_name = "asset"

urlpatterns = [
    path('ecs-create', views.EcsCreateView.as_view(), name='ecs-create')
]
  • templates/base/_js.html
<script type="text/JavaScript">
    $.ajaxSetup({headers: {"X-CSRFToken": '{{ csrf_token }}'}});
</script>

<script>

    $(document).ready(function () {   
        $('.dataTables-example').DataTable({

            "oLanguage": {
                "sLengthMenu": "Display per page _MENU_ Bar record",
                "sZeroRecords": "Sorry, we can't find any relevant data",
                "sInfo": "Current display _START_ reach _END_ A total of _TOTAL_Bar record",
                "sInfoEmtpy": "No data found",
                "sInfoFiltered": " Data sheet is _MAX_ Bar record",
                "sProcessing": "Loading...",
                "sSearch": "search",
                "oPaginate": {
                    "sFirst": "First page",
                    "sPrevious": " Previous page ",
                    "sNext": " next page ",
                    "sLast": " last page "
                }
            },
             dom: '<"html5buttons"B>lTfgitp,',
            buttons: [ 'copy', 'csv', 'excel' ]
        });

        $('.dataTables-code').DataTable({

            "oLanguage": {
                "sLengthMenu": "Display per page _MENU_ Bar record",
                "sZeroRecords": "Sorry, we can't find any relevant data",
                "sInfo": "Current display _START_ reach _END_ A total of _TOTAL_Bar record",
                "sInfoEmtpy": "No data found",
                "sInfoFiltered": " Data sheet is _MAX_ Bar record",
                "sProcessing": "Loading...",
                "sSearch": "search",
                "oPaginate": {
                    "sFirst": "First page",
                    "sPrevious": " Previous page ",
                    "sNext": " next page ",
                    "sLast": " last page "
                }
            },
            bFilter: false,
            "order": [[1, 'desc']],
            "info": false,//Show footer information or not
            destroy: true,
            "ordering": false,
            dom: '<"html5buttons"B>lTfgitp,',
            buttons: [],
            lengthMenu: [[-1], ["whole"]],
            "paging": false, // No paging
        });

    });

    $(function () {
        $(".select2").select2();
    });

</script>
  • templates/base/_nav.html
                <ul class="nav nav-second-level">
                    {% if perms.asset.add_ecs %}   Authority judgement
                        <li class="ecs-create">
                            <a href="{% url "asset:ecs-create" %}">Add assets</a>    ## Page skipping
                        </li>
                    {% endif %}
                       {% if perms.asset.view_ecs %}
                        <li class="ecs-list">
                            <a href="{% url "asset:ecs-list" %}">List of assets</a>
                        </li>
                    {% endif %}
                </ul>
  • templates/asset/ecs-create.html
    <form enctype="multipart/form-data" method="post" class="form-horizontal" action="">
                        {% csrf_token %}
                        {% if form.non_field_errors %}
                            <div class="alert alert-danger" style="margin: 20px auto 0px">
                                {{ form.non_field_errors }}
                            </div>
                        {% endif %}

                        <div class="form-group">
                            <div class="col-sm-10 col-sm-offset-0">
                                <h3>basic</h3>
                                {% 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" %}
                            </div>
                        </div>

                        <input type="hidden" name="__next__" value="{{ i__next__ }}">
                        <div class="hr-line-dashed"></div>

                        <div class="form-group">
                            <div class="col-sm-4 col-sm-offset-3">

                                {% bootstrap_button "Preservation" button_type="submit" button_class="btn-primary" %}

                                <a class="btn btn-white" href="{{ i__next__ }}">cancel</a>

                            </div>
                        </div>

                    </form>

    {% block footer-js %}

        <script>         Control left navigation deployment
            window.onload = function () {
                $(".asset").addClass("active");
                $(".ecs-create").addClass("active");
            }
        </script>

    {% endblock %}

list

  • asset/views.py
def get_list(function):
    """
    //List page get search
    :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 wrapped

class 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  ## Processing query
    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  # Return the query criteria to the front end
        }

        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
   <div class="table-responsive">

        <form class="form-horizontal  "
              method="post">
            {% csrf_token %}
            <table class="table table-striped table-bordered table-hover dataTables-code">
                <thead>
                <tr>

                    <th>host name</th>
                    <th>Host type</th>

                    <th>Example ID</th>
                    <th>Label</th>
                    <th>System version</th>
                    <th>Intranet IP</th>

                    <th  {% if request.GET.order_by == "-c_time" %}
                        class="sort_asc_png" onclick="window.location.href='?order_by=c_time'"
                    {% elif request.GET.order_by == "c_time" %}
                        class="sort_desc_png"
                        onclick="window.location.href='?order_by=-c_time'"
                    {% else %}
                        class="sort_both_png" onclick="window.location.href='?order_by=c_time'"
                    {% endif %}>Creation time
                    </th>
                    <th>operation</th>
                </tr>
                </thead>
                <tbody>
                {% for   row   in   ecs_list.object_list %}

                    <tr class="gradeA" id="{{ row.id }}" name="{{ row.hostname }}">

                        <td class="center">
                            <div class="">{{ row.hostname }}</div>
                        </td>
                        <td class="center">
                            <div class="">{{ row.get_type_display }}</div>
                        </td>
                        <td class="center">
                            <div class="">{{ row.instance_id }}</div>
                        </td>
                        <td class="center">
                            <div class="">{{ row.instance_name }}</div>
                        </td>
                        <td class="center">
                            <div class="">{{ row.os_name }}</div>
                        </td>
                        <td class="center">
                            <div class="">{{ row.private_ip }}</div>
                        </td>
                        <td class="center">
                            <div class="">{{ row.c_time |  date:'Y-m-d' }}</div>
                        </td>
                        <td>
                      {% if perms.asset.view_ecs %}
                                <a class="btn btn-success  btn-xs "
                                   href="{% url  "asset:ecs-detail" pk=row.id %}">details</a>
                            {% endif %}
                            {% if perms.asset.change_ecs %}
                                <a class="btn btn-primary  btn-xs "
                                   href="{% url  "asset:ecs-update" pk=row.id %}">edit</a>
                            {% endif %}
                            {% if perms.asset.delete_ecs %}
                                <a class="btn btn-danger  btn-xs ecs-delete"
                                   href="#> > delete </a>
                            {% endif %}
                        </td>
                    </tr>
                {% endfor %}
                </tbody>

            </table>

                         <div style="text-align:center;">

                <nav class="pagination">
                    <li><a href="{% url "asset:ecs-list" %}?page=1">home page </a></li>

                    {% if ecs_list.has_previous %}
                        <li class="long"><a
                                href="?{{ ecs_list.previous_page_number.querystring }}">Previous page</a>
                        </li>
                    {% endif %}

                    {% for page in ecs_list.pages %}
                        {% if page %}
                            {% ifequal page ecs_list.number %}
                                <li class="active"  ><a style="background-color: #E0E0E0" href="?{{ page.querystring }}">{{ page }}</a>
                                </li>
                            {% else %}
                                <li><a href="?{{ page.querystring }}" class="page">{{ page }}</a>
                                </li>
                            {% endifequal %}
                        {% else %}
                            <li class="none"><a href="">...</a></li>
                        {% endif %}
                    {% endfor %}
                    {% if ecs_list.has_next %}
                        <li class="long"><a
                                href="?{{ ecs_list.next_page_number.querystring }}">next page</a>
                        </li>
                    {% endif %}
                    <li>
                        <a href="{% url "asset:ecs-list" %}?page={{ ecs_list.paginator.num_pages }}">Tail page </a>
                    </li>
                    <li><span
                            style="color: #0a0a0a "> total: {{ECS [u list. Pager. Num [u pages}}} page</span>
                    </li>
                    <li><span
                            style="color: #0a0a0a "> quantity: {ECS [list. Pager. Count}}}}</span>
                    </li>
                </nav>
            </div>

        </form>

                        </div>

 {% block footer-js %}

        <script>
            window.onload = function () {   // Fix left navigation bar
                $(".asset").addClass("active");
                $(".ecs-list").addClass("active");
            };

            var filter_dict = {{ filter_dict | safe}};   // After the search, you can also save the search items
            $("#hostname").val(filter_dict['hostname__icontains']);
            $("#type").val(filter_dict['type']);

        </script>

To update

  • 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:  # To get the browsing page before clicking this page
            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-<int:pk>', views.EcsUpdateView.as_view(), name='ecs-update'),
  • templates.py/asset/ecs-create.html create a page while updating the page
     {% if perms.asset.change_ecs %}
        <a class="btn btn-primary  btn-xs "
           href="{% url  "asset:ecs-update" pk=row.id %}">edit</a>
    {% endif %}

delete

  • 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 %}
 <a class="btn btn-danger  btn-xs ecs-delete"  href="#> > delete </a>
  {% endif %}
   $(function () {

                $(document).on('click', '.ecs-delete', function () {
                    var id = $(this).parent().parent().attr('id');
                    var name = $(this).parent().parent().attr('name');
                    swal({
                        title: "Are you sure to delete",
                        text: name,
                        type: "warning",
                        showCancelButton: true,
                        confirmButtonColor: "#DD6B55",
                        confirmButtonText: "Determine",
                        cancelButtonText: "cancel",
                        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: "delete", text: "Successfully deleted", type: "success"}, function () {
                                        window.location.reload();
                                    })
                                } else {
                                    swal("error", "delete" + "[ " + obj.error + " ]" + "Encountered errors", "error");
                                }
                            }
                        });
                    });

                });

            });

details

  • 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-<int:pk>', views.EcsDetailView.as_view(), name='ecs-detail'),

  • templates.py/asset/ecs-list.html
    <table class="table">
        <tbody>
        <tr>
            <td style=" border-top: none !important;" width="20%">Host type:</td>
            <td style=" border-top: none !important;"><b>{{ ecs.get_type_display }}</b>
            </td>
        </tr>
        <tr>
            <td width="20%">Example ID:</td>
            <td><b>{{ ecs.instance_id }}</b>
            </td>
        </tr>
        <tr>
            <td width="20%">Label:</td>
            <td><b>{{ ecs.instance_name }}</b>
            </td>
        </tr>

        <tr>
            <td width="20%">System version:</td>
            <td><b>{{ ecs.os_name }}</b>
            </td>
        </tr>

        <tr>
            <td width="20%">CPU:</td>
            <td><b>{{ ecs.cpu }}</b>
            </td>
        </tr>

        <tr>
            <td width="20%">Memory:</td>
            <td><b>{{ ecs.memory }}</b>
            </td>
        </tr>
        <tr>
            <td width="20%">Intranet IP:</td>
            <td><b>{{ ecs.private_ip }}</b>
            </td>
        </tr>
        <tr>
            <td width="20%">Extranet IP:</td>
            <td><b>{{ ecs.public_ip }}</b>
            </td>
        </tr>
        <tr>
            <td width="20%">Creation time:</td>
            <td><b>{{ ecs.c_time }}</b>
            </td>
        </tr>
        <tr>
            <td width="20%">Update time:</td>
            <td><b>{{ ecs.u_time }}</b>
            </td>
        </tr>

        </tbody>
    </table>

Tags: Linux Django github Pycharm JSON

Posted on Sat, 02 Nov 2019 23:32:39 -0400 by vampke