在Django视图中使用subprocess.Popen()执行Python脚本

6 投票
2 回答
5426 浏览
提问于 2025-04-16 00:35

我查了一下,但似乎找不到解决我这个问题的方法。我想在我的Django应用的一个视图中执行一个Python脚本。我把想执行的代码放在了Django的管理命令里,这样就可以通过命令行来访问,命令是python manage.py command-name。然后我尝试用subprocess.Popen("python manage.py command-name",shell=True)来运行这个命令。

不过,这个命令可能需要一些时间来执行,所以我希望视图能够继续运行,并且让脚本在后台执行。单独使用subprocess.Popen似乎会导致视图卡住,直到脚本执行完毕,所以我尝试使用线程(参考了另一个StackOverflow的问题):

class SubprocessThread(threading.Thread):
def __init__(self, c):
    self.command = c
    self.stdout = None
    self.stderr = None
    threading.Thread.__init__(self)

def run(self):
    p = subprocess.Popen(self.command,
                         shell=True,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)

    self.stdout, self.stderr = p.communicate()

然后执行它:

t = SubprocessThread("python manage.py command-name")
t.setDaemon(True)
t.start()
t.join()

但是,视图还是卡住了:光标显示忙碌的符号,页面上的AJAX也没有加载。其他的HTML内容似乎正常加载,而在线程调用之后的视图中的命令也正常完成(在脚本完成之前)。有人能帮帮我吗?我希望这个脚本能够执行并自己运行,而不影响视图或页面上的AJAX调用。

2 个回答

2

我花了很多时间尝试实现类似的东西,但遇到的问题和你一样。最后,我放弃了,改用一个叫做“beanstalk”的队列来处理工作。

http://kr.github.com/beanstalkd/

我在Django的视图中给队列加了个ID,然后用一个管理命令来运行消费者(由supervisord监控)。

使用队列的好处是,你可以扩展到多个消费者,这样可以更好地管理工作负载(如果需要的话,可以暂停消费者,而不会丢失需要完成的工作)。

4

也许你应该使用celery

Celery 是一个任务队列/工作队列,它是基于分布式消息传递的。它主要用于实时操作。

撰写回答