2016-07-22 67 views
0

我想實例化一個django.test.client.Client()rest_framework.test.APIClient(),POST一組簡單參數,並從djangorestframework基於類的視圖請求JSON格式的響應。使用Django的測試客戶端post方法創建單元測試,傳遞參數並從rest_framework請求JSON

文檔suggests我只是實例APIClient()和發佈帶有參數format='json'

rest_framework.test import APIClient 
apiclient = APIClient() 
response = apiclient.post('/api/v1/model/1/run', 
          data=request_params, format='json') 

但是隨後我的看法(一DRF視圖集自定義方法)沒有收到請求參數。跟蹤此視圖,POST參數確實將其作爲字典request.data,但request.POST.items()返回空列表。當我使用下面的代碼通過AJAX從瀏覽器發出POST請求時,request.POST.items()正確返回所有參數。只有在使用單元測試APIClient()post()方法時參數值不在request.POST.items()中。

如果我使用的APIClient().get()方法,請求參數不在request.data當它到達視圖,但它們在request.GET.items(),在QUERY_STRING傳下來。這些值從查詢字符串移到ClientHandler的WSGIRequest GET QueryDict。 在django.test.client行115 request = WSGIRequest(environ)(Django 1.9.7)中調用。這似乎並沒有發生APIClient()post()

我嘗試以下:

  • 傳遞json.dumps(request_params)到數據參數,但同樣的響應 - 我的視圖沒有看到在請求(ref)的任何參數。

  • 使用Django客戶端,傳遞content_type='application/json',帶和不帶json.dumps,但響應相同。

  • 使用Django Client,將post **額外參數設置爲HTTP_ACCEPT='application/json'(帶和不帶json.dumps) - 相同的響應。

  • HTTP_ACCEPT='application/json'(帶和不帶json.dumps)初始化Django客戶端 - 相同的響應。

  • 離開Accept HTTP標頭,後的CONTENT_TYPE參數,APIClient的格式參數定義,並增加到request_params - 這適用於Client.get請求,我的代碼看到請求參數,但rest_framework返回HTML。在此HTML中呈現的JSON顯示代碼正常工作(返回狀態202和輪詢URL,因爲它應該)。

  • .json附加到單元測試中的URL並將內容類型等保留爲默認值,但我從get_response獲得Not Found: /api/v1/model/1/run/.json

我的代碼工作正常,接受通過瀏覽器的AJAX POST請求,並且我的單元測試在使用client.get()時工作正常。它只是使用client.post()和需要返回JSON的組合,我無法工作。

我提取請求的值有:

if request.method == 'POST': 
    form_values = ((key, value) for key, value in request.POST.items()) 
else: 
    form_values = ((key, value) for key, value in request.GET.items()) 

的JavaScript發送AJAX請求,即成功並返回JSON,如下:

// Setup at the bottom of the HTML body 
$(document).ready(function(){ 
    $.ajaxSetup({ 
     data: {csrfmiddlewaretoken: "{{ csrf_token }}", format: "json" } 
    }); 
    $.ajaxSetup({ 
     beforeSend: function (xhr, settings) { 
      xhr.setRequestHeader("Accept", "application/json"); 
      if (!csrfSafeMethod(settings.type) && !this.crossDomain) { 
       xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')); 
      } 
     } 
    }); 
}); 

// Code that makes the request url=/api/v1/model/1/run, method=post 
// Only POST is permitted on the view method by decorator @detail_route(methods=['post'])) 
function run_model(event) 
{ 
    var form = $(event.target); 

    $.ajax({ 
     type: form.attr('method'), 
     url: form.attr('action'), 
     data: $("#" + form.attr('id')).serialize() + "&format=json&csrfmiddlewaretoken={{ csrf_token }}" 
    }) 
    .done(function (data, status, jqXHR) { 
     poll_instance(data.instance_id, data.model_id); 
    }) 
    .fail(function (jqXHR, status, err) { 
     var status_div = $("." + construct_div_class("model", "div", jqXHR.responseJSON.model_id)).children("div.status"); 
     if (catch_ajax_error(status_div, failed_tries, jqXHR, status, err)) { 
      setTimeout(run_model, 3000, event); 
     }; 
    }); 

    event.preventDefault(); 
}; 

頭是該接受什麼得到這個工作,format = json沒有工作。

這是接收視圖:

class ModelViewSet(viewsets.ModelViewSet): 
    @detail_route(methods=['post']) 
    def run(self, request, *args, **kwargs): 
     """ 
     Runs a model and redirects to the URL that will return the output results when ready. 
     """ 
     try: 
      instance_id = run_model(request, self.get_object().id) 

     except ParameterValidationError as e: 

     # ...  

     return Response(data={'instance_id': instance_id, 'model_id': self.get_object().id}, 
         status=status.HTTP_202_ACCEPTED) 

的形式,其提交被綁定到run_model()以上:

<form method="POST" action="/api/v1/model/3/run/" id="model-form-3"> 
    <table class="table table-striped table-bordered table-hover"> 
     <tbody><tr> 
      <th> 
       Model 
      </th> 
      <th> 
       Parameter 
      </th> 
      <th> 
       Value 
      </th> 
     </tr> 
     <tr> 
      <td> 
       Source source model of Composite (model #2) 
      </td> 
      <td> 
       GUI dim value in for POC model #89 
      </td> 
      <td> 
       <select name="5_77" id="5_77"> 
         <option value="13"> 
          Dimension description #17 
         </option> 
         <option value="14"> 
          Dimension description #18 
         </option> 
       </select> 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Source model of Composite (model #1) 
      </td> 
      <td> 
       Decimal GUI value in for POC model #64 
      </td> 
      <td> 
        <input name="4_52" id="4_52" value="123456789" type="text"> 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Second source model of Composite (model #3) 
      </td> 
      <td> 
       GUI dim value in for POC model #112 
      </td> 
      <td> 
       <select name="6_100" id="6_100"> 
         <option value="16"> 
          Dimension description #20 
         </option> 

         <option value="17"> 
          Dimension description #21 
         </option> 
        </select> 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Dependent of Composite (model #0) 
      </td> 
      <td> 
       GUI dim value in for POC model #45 
      </td> 
      <td> 
       <select name="3_33" id="3_33"> 
         <option value="7"> 
          Dimension description #11 
         </option> 
         <option value="8"> 
          Dimension description #12 
         </option> 
        </select> 
      </td> 
     </tr> 
     <tr> 
      <td> 
       Dependent of Composite (model #0) 
      </td> 
      <td> 
       Decimal GUI value in for POC model #43 
      </td> 
      <td> 
        <input name="3_31" id="3_31" value="123456789" type="text"> 
      </td> 
     </tr> 
    </tbody></table> 
    <input value="Run model" type="submit"><br><br> 
</form> 

我關於Python 3.5,Django的1.9.7,djangorestframework 3.4.0(同樣發生在3.2.1),djangorestframework-xml 1.3.0,在PyCharm 2016.1中進行調試。

+1

你能不能展示你用來使用ajax發送數據的js部分。謝謝。 – mariodev

+0

感謝@mariodev好點,我已經添加了Javascript。 – Chris

+1

不知道你爲什麼使用url查詢作爲ajax調用的數據。我們是否也可以接受接收視圖?從你到目前爲止顯示的,我認爲這只是不正確的ajax有效載荷格式... – mariodev

回答

0

原來的AJAX數據是假設 t o出現在request.data中,並且我使用錯誤的方法通過AJAX從瀏覽器提交數據。 Django rest_framework(DRF)假定來自請求的數據將以與返回給客戶端的數據相同的格式傳遞 - 在這種情況下,這兩種方式都是JSON。由於它假定對於Accept=application/json請求,傳入數據將採用JSON格式,它會自動解析它併爲您填充request.data,並且request.GETrequest.POST在請求到達您的DRF視圖時爲空。

要在AJAX請求中傳遞數據的一種形式,我使用jquery form plugin's.formSerialize()方法。

我確實只是有一個.map()從窗體編譯字典,但這不適用於無線電和其他情況下,您可能有多個值爲單個鍵/窗體ID。

這個答案的信貸應該真的去@dhke,誰指出了我的根本錯誤。雖然也許這個問題應該刪除。