When sending a POST request through django-rest-framework, I get this (reformatted) exception:
django.http.request.RawPostDataException:
You cannot access body after reading from request's data stream
What's going on?
(I spent a few hours on this and I'm answering to myself StackOverflow-style in order to help others and raise awareness about the issue to the awesome django-rest-framework developers.)
Django only allows reading POST body once. This is done for various reasons:
The result is that reading POST data more than once will fail, and it is tricky to debug for two reasons:
One way to diagnose the problem to print the full traceback (with traceback.print_stack()) whenever the POST data gets read (in django/http/request.py: HttpRequest.read and HttpRequest.readline). This is how I did it, maybe there are other ways.
Okay, now what's following is the description of a possible cause when using django-rest-framework. Did you access request.method somewhere in your code? Are you using Django test client? If so, it's possible that HTTP header based method overriding kicked in. This feature allows browsers to simulate requests other than GET/POST. To do so, django-rest-framework looks at hidden form fields such as <input type="hidden" name="_method" value="DELETE">. With POST requests, this information is in the request body, so django-rest-framework will have to read the request body.
This feature is enabled by default, but django-rest-framework ensures that the request is indeed POST and is indeed using a Content-Type that would be sent on a form submission. But that's exactly the behavior of Django test client! Two possible fixes exist:
REST_FRAMEWORK = {
'FORM_METHOD_OVERRIDE': None,
'FORM_CONTENT_OVERRIDE': None,
'FORM_CONTENTTYPE_OVERRIDE': None
}
```
from django.test import Client
client = Client()
response = client.post(url, content_type='application/json')
```
Incredible, that was exactly it, looks like you read in my mind (and code)! :)
Favorite kind of support issue. Self closing, helps others out. Thanks! :sparkles:
I am trying to return a HttpResponse from another view (called from django-rest-framework view method) & I still run into this same error. The above mentioned fixes do not seem to work :(
Note: This happens when I try to read request.POST data in the view method that's returning HttpResponse object.
I'm still getting this issue, it seems that the rest-framework reads the request in the request factory
i'm getting this error whenever i'm trying to call Class based view from a generic view. I have conditions in generic view based on which particular class view is called. In Class view whenever i try to access request.data, i get _django.http.request.RawPostDataException_ error. Any help?
@api_view(['GET', 'POST'])
def HangoutPlaceSport(request):
choice = request.data['sport']
if choice == 'Hangout_sport':
return hangout_sport.as_view()(request)
class hangout_sport(APIView):
def post(self,request)
data = request.data
I'm also getting this error and can't determine what's causing it. I'm trying to use ajax to perform a post request.
$.ajax({
type: 'POST',
url: 'http://127.0.0.1:8000/api/accounts/register/',
data: JSON.stringify({something: 4}),
cache: false,
contentType: 'application/json',
dataType: 'json',
success: function(data) {
console.log(data);
},
error: function(err) {
console.log(err);
}
})
return false;
});
class UserCreateAPIView(CreateAPIView):
permission_classes = [AllowAny]
serializer_class = UserCreateSerializer
def post(self, request, *args, **kwargs):
serializer = UserCreateSerializer(data=request.data)
django.http.request.RawPostDataException: You cannot access body after reading from request's data stream is thrown in the post method of my CeateAPIView whenever I try to do request.data and the error callback is executed in the ajax with a 500 internal server error.
I have no custom middleware and I'm not accessing the request in my own code (that I know of). Is anyone having a similar issue?
UPDATE:
I think I've resolved the problem. I'm not sure why, but the error only occurs when setting a breakpoint in the post method. Removing the breakpoint fixed the problem.
Same issue for me. This error occurs when with a breakpoint in the post method with VSCode.
Hi @Rydez and @EricKit. My guess is that your issue is separate and related to #5582. Try installing the master branch and see if your issue has been fixed.
I would simply like to report that I had the same issue, and it was also caused by setting a vscode breakpoint in a GenericAPIView post() method, specifically django-rest-auth's LoginView. It'd be really great if this gotcha was included in some documentation, because If had not found this thread, I'd have lost even more hours debugging this problem!
Same weird vscode problem here, just to give visibility to the problem
ditto vscode issue
You cannot access body after reading from request's data stream
It looks as if the VSCode debugger is accessing the stream, probably as part of inspecting the frame variables. If you could detect that in action (maybe by wrapping stream to log access) then it might be something you could report the VSCode people.
This is out of scope for Django REST Framework. It's now implicitly documented here.
Just wanted to mention what was causing this for me as this is the first result on Google. I had converted a method over to use DRF and was using request.body. As soon as I switched over to request.data (which it should be) it resolved the issue for me.
I'm also getting this error and can't determine what's causing it. I'm trying to use ajax to perform a post request.
$.ajax({ type: 'POST', url: 'http://127.0.0.1:8000/api/accounts/register/', data: JSON.stringify({something: 4}), cache: false, contentType: 'application/json', dataType: 'json', success: function(data) { console.log(data); }, error: function(err) { console.log(err); } }) return false; });class UserCreateAPIView(CreateAPIView): permission_classes = [AllowAny] serializer_class = UserCreateSerializer def post(self, request, *args, **kwargs): serializer = UserCreateSerializer(data=request.data)
django.http.request.RawPostDataException: You cannot access body after reading from request's data streamis thrown in the post method of my CeateAPIView whenever I try to do request.data and the error callback is executed in the ajax with a 500 internal server error.I have no custom middleware and I'm not accessing the request in my own code (that I know of). Is anyone having a similar issue?
UPDATE:
I think I've resolved the problem. I'm not sure why, but the error only occurs when setting a breakpoint in the post method. Removing the breakpoint fixed the problem.
Which kind of break point you using with in post?
Most helpful comment
(I spent a few hours on this and I'm answering to myself StackOverflow-style in order to help others and raise awareness about the issue to the awesome django-rest-framework developers.)
Django only allows reading POST body once. This is done for various reasons:
The result is that reading POST data more than once will fail, and it is tricky to debug for two reasons:
One way to diagnose the problem to print the full traceback (with
traceback.print_stack()) whenever the POST data gets read (indjango/http/request.py:HttpRequest.readandHttpRequest.readline). This is how I did it, maybe there are other ways.Okay, now what's following is the description of a possible cause when using django-rest-framework. Did you access
request.methodsomewhere in your code? Are you using Django test client? If so, it's possible that HTTP header based method overriding kicked in. This feature allows browsers to simulate requests other than GET/POST. To do so, django-rest-framework looks at hidden form fields such as<input type="hidden" name="_method" value="DELETE">. With POST requests, this information is in the request body, so django-rest-framework will have to read the request body.This feature is enabled by default, but django-rest-framework ensures that the request is indeed POST and is indeed using a Content-Type that would be sent on a form submission. But that's exactly the behavior of Django test client! Two possible fixes exist:
REST_FRAMEWORK = { 'FORM_METHOD_OVERRIDE': None, 'FORM_CONTENT_OVERRIDE': None, 'FORM_CONTENTTYPE_OVERRIDE': None }```
from django.test import Client
client = Client()
response = client.post(url, content_type='application/json')
```