使用Django视图调用POST接口报400错误求助
我在使用Django视图调用POST接口时碰到了400错误,之前还遇到过CSRF禁用问题,现在临时用@csrf_exempt注解处理。现在出现一个奇怪的情况:
- 直接调用API时,POST参数能正常被接收(QueryDict有值),返回200状态码;
- 但通过Django视图调用这个API时,API接收到的QueryDict是空的,返回400错误。
相关日志
直接调用API日志
QueryDict: {'book': ['Second '], 'author': ['Ban'], 'date': ['2018-01-10 08:00AM']} [22/Jan/2018 18:56:09] "POST /api/test/ HTTP/1.1" 200 61
通过视图调用API日志
QueryDict: {} [22/Jan/2018 18:56:12] "POST /api/test/?book=Second+&author=Ban&date=2018-01-10+08%3A00AM HTTP/1.1" 400 36
[22/Jan/2018 18:56:12] "POST /test/ HTTP/1.1" 200 19
相关代码
models.py
class TestPost(models.Model): book = models.CharField(max_length=10, blank=True, null=True) author = models.CharField(max_length=10, blank=True, null=True) date = models.DateTimeField(blank=True, null=True)
serializer.py
class TestPostSerializer(serializers.ModelSerializer): date = serializers.DateTimeField(format="%Y-%m-%d %I:%M %p") class Meta: model = TestPost fields = ('id', 'book', 'author', 'date')
views.py
from django.http import HttpResponse import requests def my_django_view(request): if request.method == 'POST': r = requests.post('http://127.0.0.1:8000/api/test/', params=request.POST) else: r = requests.get('http://127.0.0.1:8000/api/test/', params=request.GET) if r.status_code == 200: return HttpResponse('Yay, it worked') return HttpResponse('Could not save data') class TestPostViewSet(viewsets.ModelViewSet): permission_classes = [AllowAny] queryset = TestPost.objects.all() serializer_class = TestPostSerializer
兄弟,这问题我一眼就瞅出来了!你在my_django_view里调用requests.post的时候用了params=request.POST,这完全用错参数了啊!
params是用来把数据塞到URL的查询字符串里的(就是GET请求那种?key=value的形式),但POST请求的参数应该放到请求体里,得用data参数才行!你看日志里通过视图调用的那条,URL后面跟着一堆book=Second+&author=Ban...,这说明你把本该放在请求体里的POST参数全塞到URL里了,而你的API接口是期望从请求体拿POST数据的,自然就拿到空的QueryDict,返回400错误了。
修正后的代码
把my_django_view里的params改成data就搞定了:
def my_django_view(request): if request.method == 'POST': # 把params换成data,让POST数据进入请求体 r = requests.post('http://127.0.0.1:8000/api/test/', data=request.POST) else: r = requests.get('http://127.0.0.1:8000/api/test/', params=request.GET) if r.status_code == 200: return HttpResponse('Yay, it worked') return HttpResponse('Could not save data')
另外提个小建议:@csrf_exempt只是临时救急的方案,正式环境里最好还是正确处理CSRF验证,比如在请求里带上CSRF token,这样更安全。
内容的提问来源于stack exchange,提问作者Jin Nii Sama

