2015-11-09 28 views
0

我有一個查詢表單,可以從服務器上的數據生成一個大的json對象。理想情況下,在提交時,應將用戶重定向到從AJAX請求更新的結果頁面(+進度欄),直到結果生成並準備顯示。django視圖+ AJAX:如何檢索表單POST後的數據

當前,當用戶提交表單時,它們將留在queryForm頁面上,同時生成結果。 dataFromQuery完成後實現回調的正確django方法是什麼?

這是我基於類的視圖的精簡版:

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沒有被傳遞到:

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()結果對象一旦完成。

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上檢索,但行:results ['data'] = dataFromQuery在生成結果後不會更新。

回答

0

考慮使用一些任務隊列/管理器,如celery。只需創建能夠產生結果的任務,以某種方式監視它,並向用戶顯示創建響應的當前進度。

0

HTTP與請求 - >響應一起工作。 Django無法將消息(如進度)「推送」給瀏覽器,而無需詢問。 你可以做的是使用輪詢,每隔X秒發送一次ajax請求以獲取狀態。 這個解決方案並不是那麼簡單的創建,因爲您需要一個可以返回進度的獨立函數,並且可以在單獨的線程(異步)中執行進度。

根據情況,更容易的解決方案是讓用戶知道數據正在處理中,例如使用spinner

+0

進展的作品(我每秒做一個ajax請求檢查results.progress,我已經有一個微調的提交按鈕,我想要的知道是否可以在django視圖中進行回調以將POST方法中的數據導入結果數據對象。 – Liz

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
+0

感謝您的詳細回覆 - 將嘗試並報告進度 – Liz

相關問題