I need your help, In my view i run a bash process that takes time depending on the size of the image; while it process i want to display a loading gif image and a sentence (such as "Please wait, the image is being processed"). I tried to did that with a template but it is rendered at the end of execution of the script not while it process. Can someone help me to do that ? I've found a similar question "Django - show loading message during long processing" but the answer wasn't very clear for me because i never used ajax.
This is my view :
def process(request):
var = Image.objects.order_by('id').last()
subprocess.call("./step1.sh %s" % (str(var)), shell=True)
subprocess.call("./step2.sh %s" % (str(var)), shell=True)
return render(request, 'endexecut.html')
Template that will be displayed at the end of processing: "endexecut.html"
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div class="row">
<div class="jumbotron">
<div class="row">
<center>
<p> Your image is processed succesfully ! </p>
</center>
</div>
</div>
</div>
{% endblock %}
答案 0 :(得分:2)
您应该查看Celery,它可以让您创建作业并对其进行监控。这将取代您的process(request)
。使用您自己的process(request)
,您必须自己实现,如果已经存在解决方案,为什么要这样做。
使用浏览器中的JS(AJAX)可以像这样查询正在运行的子进程的状态:
def task_progress_json(request, job_id):
"""
A view to report the progress to the user
:param job_id:
:param request:
"""
job = AsyncResult(job_id)
data = job.result or job.state
if job.state == states.FAILURE or isinstance(data, Exception):
data = {'failure': "{}: {}".format(_('Error'), data)}
if job_id in request.session:
request.session[job_id] = None
else:
# see http://docs.celeryproject.org/en/latest/reference/celery.states.html#std:state-PROPAGATE_STATES
# and http://docs.celeryproject.org/en/latest/getting-started/next-steps.html#calling-tasks
if data == states.PENDING:
last_state = request.session.get(job_id, None)
if last_state == states.PENDING:
data = {'failure': "Error: No Job Running"}
request.session[job_id] = None
else:
request.session[job_id] = data
if isinstance(data, dict):
next_url = data.pop('next_url', None)
next_kwargs = data.pop('next_kwargs', {})
if next_url:
data['next_url'] = reverse(next_url, kwargs=next_kwargs)
return HttpResponse(json.dumps(data), content_type='application/json')
在触发流程的视图中,例如当用户点击表单的Submit
按钮时,您就会启动该作业:
def form_valid(self, form):
# this is just an example, implement as you like
fs = FileSystemStorage(location=settings.IMAGE_ROOT)
stored_file = fs.save(form.cleaned_data['file'].name, form.cleaned_data['file'])
job = import_imag_task.delay(stored_file, self.request.user.id, self.spectre.id)
# this is another view that shows the progress bar
# the process of the progress bar is displayed according to
# results fetched from the above task_progress_json request via AJAX
return HttpResponseRedirect(reverse('import_image_progress') + '?job=' + job.id)
答案 1 :(得分:1)
你最好的拍摄是使用ajax。您只需将视图重写为:
def process(request):
return render(request, "endexecut.html")
默认情况下,使用您要使用的任何文本在endexecut模板中显示gif图像。
在模板页面的脚本部分,您可以进行如下的ajax调用:
$.ajax({
url: '/some-app/some-view/',
type: 'GET',
dataType: 'json',
success: function(result){
$('#image-id').attr('src', result.image);
},
error: function(xhr){
alert(xhr.responseText); //Remove this when all is fine.
}
});
Ajax指向一个url(你应该在你的url.py中定义),url会指向可以进行长时间bash处理的视图:
def bash_processing(request):
# Do your bash processing here
return JsonResponse({'image': 'image url here'})
这应该对你有用。
但是,如果处理需要很长时间,您可以考虑使用celery
在后台进行处理。
答案 2 :(得分:0)
我遇到了同样的问题并使用了jquery和ajaxcall。这样,您可以在启动上传时显示gif,并在完成后移除gif。