我有一个查询表单,它可以从服务器上的数据生成一个大型json对象。理想情况下,在提交时,用户应该被重定向到从AJAX请求得到更新的结果页面(+进度栏),直到生成结果并准备显示为止。
当前,当用户提交表单时,当生成结果时,它们会被挂在queryForm页面上。在dataFromQuery完成后,实现回调的正确django方法是什么?
下面是基于类的视图的简化版本:
class QueryForm(generic.View):
form_class = ReturnQuery
template_name = 'myapp/form/queryForm.html'
def get(self, request, *args, **kwargs):
#render form
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
# <process form cleaned data>
print(request.POST)
print(form.cleaned_data)
# continues to build results object (json) which can take
# any length of time
return render(request, 'myapp/form/queryResults.html', {
'dataFromQuery': dataFromQuery,
})
我在POST方法中尝试了is_ajax():
if request.is_ajax():
results = { "progress" : {'progress':1} }
try:
dataFromQuery
except NameError:
dataFromQuery_exists = False
else:
dataFromQuery_exists = True
results['data']=dataFromQuery
return JsonResponse(results)
但是,一旦dataFromQuery完成,它就不会被传递给结果对象。
联署材料:
var refreshIntervalId = setInterval(function(){
$.ajax({type: "POST",url: '/website/queryForm/', data: {csrfmiddlewaretoken : csrftoken}, dataType:'json', success: function(results){ //do something with results }})
});
我已经看过模板响应,但我不知道它们在这里如何帮助,因为在页面呈现完成后,回调看起来就执行了。任何帮助都将不胜感激。
编辑:我可能有点不清楚。results.progress是在成功的AJAX上检索的,但是这一行:结果‘’data‘=dataFromQuery在生成结果后不会更新。
发布于 2015-11-09 02:29:25
考虑使用一些任务队列/管理器,比如芹菜。只需创建将产生您的结果的任务,以某种方式监视它,并向用户显示创建响应的当前进度。
发布于 2015-11-09 02:30:24
HTTP适用于请求->响应。Django不能在没有请求的情况下将消息(如进度)“推”到浏览器。您可以做的是使用轮询,它每隔X秒发送一个ajax请求来获取状态。创建此解决方案并不那么简单,因为您需要一个返回进度的分离函数,并在分离线程(异步)中执行实际执行过程。
根据具体情况,一个更简单的解决方案是让用户知道数据正在被处理,例如使用一个微调器。
发布于 2015-11-10 02:12:52
我目前正在发展一个非常类似的案例。你想做的事情并不是那么琐碎。不幸的是Django本质上是完全同步的,因此AJAX调用将在Python端阻塞。
正如已经建议的那样,使用某种任务管理工具。我使用芹菜,这是容易使用和充分结合在Django。
您的代码将如下所示
class QueryForm(generic.View):
...
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
token = generate_request_token()
if form.is_valid():
celery_task.apply_async(<token>, <parameters>) <-- this returns immediately
return render(request, 'myapp/form/queryResults.html', {
'token': <token>,
})
您的celery_task现在正在计算背景中的结果,并将在完成后存储结果。你想把结果存储在哪里是你的选择。
您仍然需要创建另一个Django端点才能得到结果。将其映射到www.yoursite.com/queryForm/data之类的地方。就像这样
def get(self, request, *args, **kwargs):
#return data in JSON format
return JsonResponse(get_data_from_storage(request.<token>))
get_data_from_storage将查看结果存储,并检查结果是否已就绪或部分就绪。(另一种方法是检查celery_task的状态。当它完成时,结果必须准备好)
然后在JS端,一旦用户提交QueryForm,他就被重定向到www.yoursite.com/queryResults.html/TOKEN (结果页面),或者找到将令牌传递到结果页面的方法。
现在您可以做的是使用令牌查询后端中属于该令牌的数据。一旦进入结果页面,就会执行类似的操作。
var refreshIntervalId = setInterval(function(){
$.ajax({type: "GET", url: '/website/queryForm/data', data: {token: <token>}, dataType:'json', success: function(results){ if (results) {// do something} }})
});
上面的JS方法称为连续轮询,它不是最优的。(有关替代方案,请参阅Socket.io,但您将需要像Node.js这样的附加组件,我是这样做的)。渲染最终在前端完成。每次获得新结果时,都会使用新的数据更新页面。
还有其他的方法,但目前我觉得这是最直接的方法。
芹菜的替代品有:
https://stackoverflow.com/questions/33606571
复制