(PHPでいう、output_buffering を切った感じです)
StreamingHttpResponse を使います。
StreamingHttpResponse の第一引数はジェネレータなので、バッチをジェネレータで書きます。
今回の例は、シェルコマンドをジェネレータにしています。
import subprocess
from django.http import StreamingHttpResponse
from django.utils.encoding import smart_str
from django.utils.html import escape
from django.views import View
def run_process_as_generator(*args, **kwargs):
"""
サブプロセス結果をジェネレータで返す
:rtype: generator
"""
kwargs.setdefault('stdout', subprocess.PIPE)
kwargs.setdefault('stderr', subprocess.STDOUT)
popen = subprocess.Popen(*args, **kwargs)
while True:
line = popen.stdout.readline()
if line:
yield line
if not line and popen.poll() is not None:
break
def linebreaksbr(gen):
"""
ジェネレータの各行に<br />をつける
念のため smart_str
:type gen: generator
:rtype: generator
"""
for line in gen:
yield '{}<br />\n'.format(escape(smart_str(line)))
def task():
"""
バッチを実行
:rtype: generator
"""
return linebreaksbr(
run_process_as_generator(
"for i in {1..10}; do sleep 1s; echo ${i}; done",
shell=True
))
class SlowCommandView(View):
"""
task() の結果を少しずつブラウザに返すビュー
"""
def get(self, request, *args, **kwargs):
response = StreamingHttpResponse(
task(),
content_type="text/html; charset=utf-8")
return response
Python でバッチを書く場合は、print でログを書くかわりに yield を使うと良いと思います。
def task():
yield 'start'
...
yield 'phase-1'
...
for xx in xxx:
yield xx
yield 'end'
参考:
Pythonのsubprocessで標準出力をリアルタイムに取得する - Qiita
Request and response objects | Django documentation | Django