我想实例化django.test.client.Client()
或rest_framework.test.APIClient()
,POST一组简单的参数,并从基于djangorestframework类的视图请求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参数确实将其作为dict转到request.data
,但request.POST.items()
返回一个空列表。当我使用下面的代码从浏览器通过AJAX发出POST请求时,request.POST.items()
会正确返回所有参数。只有在使用单元测试APIClient()
post()
方法时,参数值才会在request.POST.items()
中。
如果我使用.get()
的{{1}}方法,请求参数在到达视图时不在APIClient()
中,但它们位于request.data
中,传入request.GET.items()
。 ClientHandler中的值从查询字符串移动到WSGIRequest GET QueryDict。调用在django.test.client第115行QUERY_STRING
(Django 1.9.7)中。 request = WSGIRequest(environ)
APIClient()
似乎没有发生这种情况。
我尝试了以下内容:
将post()
传递给数据参数,但响应相同 - 我的视图未看到请求中的任何参数(ref)。
使用Django客户端,传递json.dumps(request_params)
,有和没有json.dumps,但响应相同。
使用Django Client,将post **额外参数设置为content_type='application/json'
(有和没有json.dumps) - 相同的响应。
使用HTTP_ACCEPT='application/json'
(有和没有json.dumps)初始化Django客户端 - 相同的响应。
保留HTTP_ACCEPT='application/json'
HTTP标头,发布的content_type参数和APIClient的格式参数未定义,并将Accept
添加到request_params - 对于{'format':'json'}
请求,我的代码会看到请求参数,但rest_framework会返回HTML。在此HTML中呈现的JSON显示代码正常工作(返回状态202和轮询URL,应该如此)。
将Client.get
附加到单元测试中的网址,并将内容类型等保留为默认值,但我从get_response获取.json
。
我的代码可以通过浏览器接受AJAX POST请求,当我使用client.get()时,我的单元测试工作正常。它只是使用client.post()和需要JSON的组合,我无法工作。
我用以下内容提取请求值:
Not Found: /api/v1/model/1/run/.json
发送AJAX请求的Javascript,成功并返回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())
Accept标头是这个工作的原因,格式= 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();
};
表单,其提交与上面的run_model()相关联:
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)
我在Python 3.5,Django 1.9.7,djangorestframework 3.4.0(也发生在3.2.1),djangorestframework-xml 1.3.0,在PyCharm 2016.1中进行调试
答案 0 :(得分:0)
证明AJAX数据假设出现在request.data
中,我使用错误的方法从浏览器通过AJAX提交数据。 Django rest_framework(DRF)假设来自请求的数据将以与返回给客户端的数据相同的格式传递 - 在这种情况下是JSON两种方式。因为它假定对于Accept=application/json
请求,传入的数据将采用JSON格式,它会自动解析它并为您填充request.data
,request.GET
和request.POST
为空请求到达DRF视图的时间。
要在AJAX请求中传递数据形式,我使用jquery form plugin's .formSerialize()
方法。
我只是从表单中编译了一个.map()
字典,但这对于无线电和其他可能有多个值的单个键/表单ID的实例不起作用。
这个答案应该归功于@dhke,他指出了我的根本错误。虽然也许应该删除这个问题。