如何将变量从 CLI 程序传递到 Python 视图以更新 Django UI?

Posted

技术标签:

【中文标题】如何将变量从 CLI 程序传递到 Python 视图以更新 Django UI?【英文标题】:How to pass variable from CLI program to Python Views to Update Django UI? 【发布时间】:2018-11-24 18:25:35 【问题描述】:

我有一个 Django 应用程序,它通过函数调用调用 CLI 应用程序,然后 CLI 应用程序执行操作并提供输出。 CLI 版本有一个显示进程进度的加载栏,我的计划是将它与 GUI 集成。这个项目很大,所以我把它简化为一个更短的项目,让你们清楚地理解。真正的应用程序比这个演示应用程序更细微和复杂

所以,我创建了一个小型演示项目来为大家简化问题。 项目结构是

│   db.sqlite3
│   manage.py
│
├───testapp
│   │   admin.py
│   │   apps.py
│   │   models.py
│   │   tests.py
│   │   views.py
│   │   views.pyc
│   │   __init__.py
│   │   __init__.pyc
│   │
│   ├───cliprog
│   │       cliprogram.py
│   │       cliprogram.pyc
│   │       main.py
│   │
│   └───migrations
│           __init__.py
│
└───testproject
        settings.py
        settings.pyc
        urls.py
        urls.pyc
        wsgi.py
        wsgi.pyc
        __init__.py
        __init__.pyc

views.py

from django.shortcuts import render
from django.http import HttpResponse
from django.conf import settings
from cliprog.main import view_helper

def index(request):
    view_helper()
    return HttpResponse('It works but CLI')

cliprog/main.py

from cliprogram import nice

def view_helper(): # So, that I can call this function and run my cli code
    # do something
    nice()
    # do something

cliprog/cliprogram.py

# Print iterations progress
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '#'):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
    """
    percent = ("0:." + str(decimals) + "f").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    bar = fill * filledLength + '-' * (length - filledLength)
    print '\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix)
    # Print New Line on Complete
    if iteration == total:
        print()

#
# Sample Usage
#

from time import sleep
def nice():
# A List of Items
    items = list(range(0, 57))
    l = len(items)

# Initial call to print 0% progress
    printProgressBar(0, l, prefix = 'Progress:', suffix = 'Complete', length = 50)
    for i, item in enumerate(items):
    # Do stuff...
        sleep(0.1)
    # Update Progress Bar
        printProgressBar(i + 1, l, prefix = 'Progress:', suffix = 'Complete', length = 50)

因此,当您运行 python manage.py runserver 时,其想法是视图运行 CLI 程序来计算百分比(使用总值和当前样本数)。但在 CLI 上显示它,因为那是一个 CLI 程序。 现在,我需要的是,我想以某种方式从 cli 文件 cliprogram.py 中获取 li(分别为总迭代和当前迭代)到视图,视图会将其传递给 UI,我将在其中实现 GUI 版本加载栏。

有没有可能性,当函数nice() 被触发时,它可以将值传递给views.py,以便我可以更新加载栏的GUI 版本?

注意: 我已经将芹菜用于真正的应用程序。只是没有在演示应用程序中显示。所以,如果有什么事情可以用 celery 来解决。欢迎回答

【问题讨论】:

【参考方案1】:

选项 1

在你的 CLI 中添加一个命令行标志,--no-bar 或其他东西。当--no-bar 启用时,不显示进度条,只打印百分比。您的 GUI 可以将百分比作为流读取并相应更新。

注意:CLI 中的其他打印语句可能会搞砸。

选项 2

将进度条打印到stderr,但将百分比打印到stdout。在您的 GUI 中只读 stdout

【讨论】:

问题是如何通过views.py 从 CLI 的 stdout 检索这些值。 views.py 和 GUI 相互链接。因此,为了将任何内容更新到 GUI。这个想法是首先获取到views.py。但最棘手的部分是将数据发送到views.py。你有什么想法吗【参考方案2】:

因为django 本质上是单线程单进程,我认为您需要使用multiprocessingthreading 库来做到这一点。您的想法涉及同时运行两段代码。您可以打开管道在进程之间传递变量,或者如果您使用threading,则直接读取变量。由于您提供的示例已简化,因此我不想在这里修改您的代码,因为它涉及对整个项目的重大修改。

我稍微修改了您的演示,使其可以作为独立脚本而不是 django 项目运行。但想法还是一样。

import multiprocessing as mp


# Print iterations progress
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '#'):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
    """
    percent = ("0:." + str(decimals) + "f").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    bar = fill * filledLength + '-' * (length - filledLength)
    print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix))
    # Print New Line on Complete
    if iteration == total:
        print()

#
# Sample Usage
#

from time import sleep
def nice(connection):
# A List of Items
    items = list(range(0, 57))
    l = len(items)

# Initial call to print 0% progress
    printProgressBar(0, l, prefix = 'Progress:', suffix = 'Complete', length = 50)
    for i, item in enumerate(items):
    # Do stuff...

        sleep(0.1)
    # Update Progress Bar
        connection.send((i,l))
        printProgressBar(i + 1, l, prefix = 'Progress:', suffix = 'Complete', length = 50)
    connection.close()

def view_helper(connection): # So, that I can call this function and run my cli code
    # do something
    nice(connection)
    # do something

def index(): # your django view
    conn1,conn2=mp.Pipe()
    p=mp.Process(target=view_helper,args=(conn2,))
    p.start()
    while True:
        i,l=conn1.recv()
        # do things you want with your i and l
        if i==l-1:
            conn1.close()
            p.terminate()
            break

    #return HttpResponse('It works but CLI')

index()

【讨论】:

听起来很合理。您可以根据需要修改演示项目,我将尝试复制它,看看是否可以与原始项目集成。因为它有点棘手。 我已经在使用芹菜了,芹菜本身有更好的功能吗? @pkqxdd 我对芹菜不是很熟悉。但我已经用一个工作演示编辑了我的答案。

以上是关于如何将变量从 CLI 程序传递到 Python 视图以更新 Django UI?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 process.env 将环境变量中的 API 密钥传递给 Ember CLI?

如何将变量从 python Django 传递到 HTML 模板

如何使用nodejs(给1个特定用户)将变量从一个页面传递到另一个页面?

SwiftUI MVVM 将变量从 ViewModel 传递到 API 服务

如何通过 C++-CLI 回调和委托将字符串从 C++-CLI 传递到 C#

如何将变量从 AIR 应用程序传递到外部 SWF