2022-01-09 在Django 4.0中实现Web方式执行系统命令和结果显示 (1)

Web方式执行系统命令和结果显示,就是在 Web页面上输入 Windows 或 Linux 的系统命令或脚本执行,把执行结果显示在 Web 页面上。

1. 开发环境

    Windows 10 Home (20H2) or Ubuntu 18.04

    Python 3.8.1

    Pip 21.3.1

    Django: 4.0

    Windows下搭建开发环境,请参考Windows下搭建 Django 3.x 开发和运行环境

    Ubuntu下搭建开发环境,请参考Ubuntu下搭建 Django 3.x 开发和运行环境


2. 创建 Django 项目

     > django-admin startproject djangoShellDemo


3. 添加 App

     > cd djangoShellDemo

     > python manage.py startapp home

     生成的项目目录结构,参考如何在Django中使用template和Bootstrap

        修改 djangoShellDemo/settings.py

        ALLOWED_HOSTS = ['localhost', '192.168.0.5']

        ...

        INSTALLED_APPS = [

            ...

            'home',

        ]

        ...

        # Create static folder

        STATICFILES_DIRS = [

            BASE_DIR / 'static',

        ]


4. 静态资源和模板

    1)  静态资源

        从 https://jquery.com/ 下载 jQuery 包, 添加到 :

            static/js/jquery-1.12.2.min.js

        * static 等中间目录如果不存在,请新建它们,下同。

    2) 添加 home/templates/home.html

        <!DOCTYPE html>

        <html lang="en">

        <head>

            <meta charset="utf-8">

            <title>Home Page</title>

            {% load static %}

            <script language="javascript" src="{% static 'js/jquery-1.12.2.min.js' %}"></script>   

        </head>

        <body>

            <h3>Home Page</h3>

            <form class="form-horizontal" role="form" action="" method="post" novalidate>

                {% csrf_token %}


                <p>

                    <label>System Environment:</label><br>

                    <select name="os_type" id="os_type" style="height: 32px; width: 50%">

                        <option value="windows">Server run on Windows</option>

                        <option value="ubuntu">Server run on Ubuntu</option>

                    </select>

                </p>

                <p>

                    <label>Cmd Type:</label><br>

                    <select name="cmd_type" id="cmd_type" style="height: 32px; width: 50%">

                        <option value="system_cmd_shell">System command or shell</option>

                        <option value="django_cmd_shell">Django command or shell</option>

                    </select>

                </p>

                <p>

                    <label>Command or shell:</label><br>

                    <textarea name="cmd_str" id="cmd_str" style="height: 64px; width: 50%"></textarea>

                </p>

                <p>

                    <button type="button" class="btn btn-default btn-sm" onClick="javascript: execCmd();">

                        Execute

                    </button>

                </p>

            </form> 

            <p>&nbsp;</p>

            <div style="padding: 15px; background-color: #e2e2e2; width: 50%; min-height: 120px;" id="cmd_result">

            </div>

            <p>&nbsp;</p>

            <script type="text/javascript">

                console.log("Home Page");

                $(document).ready(function() {

                    changeType();


                    $("#os_type").change(function(e) {

                        changeType();

                    });

                    $("#cmd_type").change(function(e) {

                        changeType();

                    });

                });

                function changeType() {

                    var osType = $("#os_type").val();

                    var cmdType = $("#cmd_type").val();

                    var cmdStrNode = $("#cmd_str");

                    if (osType == "windows") {

                        if (cmdType == "system_cmd_shell") {               

                            cmdStrNode.val("dir C:\\");

                            cmdStrNode.removeAttr("disabled");

                        } else if (cmdType == "django_cmd_shell") {

                            cmdStrNode.val("DirCommand C:\\");

                            cmdStrNode.attr("disabled", "disabled");

                        } else {

                        }

                    } else if (osType == "ubuntu") {

                        if (cmdType == "system_cmd_shell") {

                            cmdStrNode.val("dir /");

                            cmdStrNode.removeAttr("disabled");

                        } else if (cmdType == "django_cmd_shell") {

                            cmdStrNode.val("DirCommand /");

                            cmdStrNode.attr("disabled", "disabled");

                        } else {

                        }

                    } else {

                    }

                }


                function execCmd() {

                    var cmdType = $("#cmd_type").val();

                    var cmdStr = $("#cmd_str").val();

                    if (cmdStr == '') {

                        alert("Please enter command or shell");

                        $("#cmd_str").focus();

                        return;

                    }

                    var node = $("#cmd_result");

                    node.html("Executing command or shell ... ");

                    $.ajax({

                        type: 'POST',

                        url: "{% url 'exec_cmd' %}",

                        data: {

                            cmd_type: cmdType,

                            cmd_str: cmdStr,

                            csrfmiddlewaretoken: $("input[name='csrfmiddlewaretoken']").val(),

                        },

                        success: function(response) {

                            console.log(response);

                            if (response.ret == 'success') {

                                node.html(response.data);

                            } else if (response.ret == 'error') {

                                node.html(response.description);

                            } else {

                                node.html("Unknow error"); 

                            }

                        },

                        error: function(err) {

                            console.log(err);

                            node.html("Network error");

                        },

                    });

                }

            </script>

        </body>

        </html>


5. 视图和路由

    1) 添加 home/utils.py

        import subprocess

        def systemExecuteLines(rsyncStr, shell=True, b_print=True):

            #print(rsyncStr)

            p = subprocess.Popen(rsyncStr, shell=shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

            out, err = p.communicate()

            return out.decode("gbk", "ignore").splitlines(), err.decode("gbk", "ignore").splitlines()

        def systemExecute(rsyncStr, shell=True, b_print=True):

            #print(rsyncStr)

            p = subprocess.Popen(rsyncStr, shell=shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

            out, err = p.communicate()

            return out.decode("gbk", "ignore"), err.decode("gbk", "ignore")

        * 显示中文时需要 decode 设置为 gbk

    2) 修改 home/views.py

        from django.shortcuts import render, HttpResponse

        from django.http import JsonResponse

        from home.utils import systemExecuteLines

        # Create your views here.

        def home(request):

            return render(request, "home.html")

        def exec_cmd(request):

            if request.method == "POST":

                cmdType = request.POST.get("cmd_type", "")

                cmdStr = request.POST.get("cmd_str", "")

                print(cmdType)

                print(cmdStr)

                if cmdType == "system_cmd_shell":

                    data,err = systemExecuteLines(cmdStr)

                    if err:

                        result = {"ret": "error", "description": err}

                    else:         

                        result = {"ret": "success", "data": data}

                elif cmdType == "django_cmd_shell":

                    data,err = systemExecuteLines("python manage.py " + cmdStr)

                    if err:

                        result = {"ret": "error", "description": err}

                    else:         

                        result = {"ret": "success", "data": data}

                else:

                    result = {"ret": "error", "description": "Invalid cmd type"}

                return JsonResponse(result)

    3) 修改 djangoShellDemo/urls.py

        from django.contrib import admin

        from django.urls import path, include

        from home import views

        urlpatterns = [

            path('', views.home, name='home'),

            path('exec/cmd/', views.exec_cmd, name='exec_cmd'),

            ...

        ]


6. Django 自定义命令

    1) 添加 home/management/commands/DirCommand.py

        from django.core.management.base import BaseCommand

        from home.utils import systemExecute

        class Command(BaseCommand):

            help = "Run 'dir' command on Windows or Linux."

            def add_arguments(self, parser):

                parser.add_argument("path")

            def handle(self, *args, **options):

                data,err = systemExecute("dir " + options["path"])

                if err:

                    print(err)

                else:

                    print(data)

    2) 命令行方式运行 DirCommand

        > python manage.py DirCommand c:\          # On Windows

            Volume in drive C is WINDOWS

            Volume Serial Number is D46B-07AC

            Directory of c:\

            2021/12/28  10:57    <DIR>          Program Files

            2021/12/28  13:50    <DIR>          Program Files (x86)

            2021/12/20  12:15    <DIR>          Users

            2021/12/29  11:26    <DIR>          Virtual

            2022/01/05  18:18    <DIR>          Windows

            0 File(s)              0 bytes

            ...

        $ python manage.py DirCommand /    # On Ubuntu

            bin    dev  root    usr    etc    lib  mnt  var

            home  lib64    opt    sbin  sys  cdrom

            ...


7. 运行

    > python manage.py runserver

        访问 http://localhost:8000/  

        运行系统命令或脚本,请输入短时内返回结果的命令,比如 ubuntu 下的 ls -la /

    > python manage.py runserver 192.168.0.5:8080

        访问 http://192.168.0.5:8080/

本实例支持短时内返回结果的命令,长时运行(阻塞式)的命令和脚本,需要使用 Websocket 来实现。下篇文章实现 Websocket 方式运行系统命令。 

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。