django view + AJAX:如何在POST后检索数据

时间:2015-11-09 10:00:53

标签: javascript jquery ajax django

我有一个查询表单,可以从服务器上的数据生成一个大的json对象。理想情况下,在提交时,应将用户重定向到结果页面(+进度条),该页面将从AJAX请求更新,直到生成结果并准备好显示。

目前,当用户提交表单时,他们会在生成结果的同时将其挂在queryForm页面上。完成后,为dataFromQuery实现回调的正确方法是什么?

以下是基于类的视图的精简版:

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一旦完成就不会传递给结果对象。

JS:

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上检索的,但行:结果[&#39; data&#39;] = dataFromQuery在生成结果后不会更新。

3 个答案:

答案 0 :(得分:0)

考虑使用某些任务队列/管理器,例如celery。只需创建将产生结果的任务,以某种方式监控它并向用户显示创建响应的当前进度。

答案 1 :(得分:0)

HTTP与请求一起使用 - &gt;响应。 Django无法推动&#39;消息(如进度)到浏览器没有它询问。 您可以做的是使用轮询,每隔X秒发送一次ajax请求以获取状态。 这个解决方案创建起来并不简单,因为您需要一个单独的函数来返回进度,并在一个单独的线程中执行实现(异步)。

根据具体情况,更简单的解决方案是让您的用户知道正在处理数据,例如使用spinner

答案 2 :(得分:0)

我目前正在开发一个非常类似的案例。你要做的不是那么微不足道。不幸的是,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(结果页面),或找到将令牌传递到结果页面的方法。

您现在可以做的是使用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这样的附加组件,我就是这样做的)。渲染最终在前端完成。每次获得新结果时,都会使用最新数据更新页面。

还有其他方法,但目前这对我来说似乎最直接。

芹菜的替代品是:

  • 线程(如果你知道你在做什么)
  • RabbitMQ / ZeroMQ
  • 龙卷风(但可能不容易与Django集成)
  • GEVENT