如何将变量从 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
中获取 l
和 i
(分别为总迭代和当前迭代)到视图,视图会将其传递给 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
本质上是单线程单进程,我认为您需要使用multiprocessing
或threading
库来做到这一点。您的想法涉及同时运行两段代码。您可以打开管道在进程之间传递变量,或者如果您使用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 服务