如何将变量从 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?的主要内容,如果未能解决你的问题,请参考以下文章