django-rest-framework
django-rest-framework copied to clipboard
"No POST data" in error report
Checklist
- [X] Raised initially as discussion #7899
- [X] This cannot be dealt with as a third party library. (We prefer new functionality to be in the form of third party libraries where possible.)
- [X] I have reduced the issue to the simplest possible case.
Description
I'm using Django 3.1.7 & DRF 3.12.2.
When an exception occurs in a ViewSet, Django automatically sends an email to the administrator.
The problem is that the POST data is always empty in this email:
POST: No POST data
Instead, I expect to see the JSON payload that was sent in the request body.
I added a breakpoint in django.utils.log.AdminEmailHandler.emit(), and I can confirm that request.POST is empty.
But on the other hand, I'm sure that request.data was not empty in the ViewSet.
I verified that the request's Content-Type and X-Requested-With are correctly set.
The only non-standard middlewares I use are corsheaders and admin_reorder; I don't think they are related to this problem.
Any progress on this issue? I have the same problem.
I can also confirm this issue, and it makes it a little bit hard to trace back errors
Here is a discussion related to this problem
At this point I am convinced DRF is a dead project
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I still think this is an important feature, please don't close this issue.
I agree.
I'm also having this issue.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I still think this is an important feature, please don't close this issue.
It is because django dose not parse body of application/json to request.POST field.You can convert json string to dict by yourself, like this:
res = request.body
json_str = res.decode('utf-8')
json_dict = json.loads(json_str)
Then write a custom log handler class instead of AdminEmailHandler to send your own dict data converted from json.
some code snippet:
def emit(self, record):
try:
request = record.request
subject = '%s (%s IP): %s' % (
record.levelname,
('internal' if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS
else 'EXTERNAL'),
record.getMessage()
)
import json
from django.http import QueryDict
json_str = request.body.decode('utf-8')
json_dict = json.loads(json_str)
query_dict = QueryDict(mutable=True)
for key in json_dict.keys():
query_dict[key] = json_dict[key]
request.POST = query_dict
except Exception as ex:
subject = '%s: %s' % (
record.levelname,
record.getMessage()
)
request = None
subject = self.format_subject(subject)
and the message is ...\n\nGET: No GET data\n\nPOST:\nusername = 'python1'\npassword = '123456'\n\nFILES: No FILES data...
Thanks, @donghj2000, this is awesome, but I still think this should be a built-in feature.
Glad to help you. I have not found why they didn't do so. Another workaround is to use Middleware:
class ParseJsonData(MiddlewareMixin):
def process_request(self, request):
if request.content_type.startswith("application/json"):
try:
json_str = request.body.decode('utf-8')
json_dict = json.loads(json_str)
query_dict = QueryDict(mutable=True)
for key in json_dict.keys():
query_dict[key] = json_dict[key]
request.POST = query_dict
except Exception as ex:
pass
Glad to help you. I have not found why they didn't do so. Another workaround is to use Middleware:
class ParseJsonData(MiddlewareMixin): def process_request(self, request): if request.content_type.startswith("application/json"): try: json_str = request.body.decode('utf-8') json_dict = json.loads(json_str) query_dict = QueryDict(mutable=True) for key in json_dict.keys(): query_dict[key] = json_dict[key] request.POST = query_dict except Exception as ex: pass
This snippet has an issue where it assumes the JSON is an object and will fail on any other valid JSON value
It seems to be a bug exactly, but request.POST is initialized as a QueryDict(django.http.request.py->class HttpRequest) ,so I don't know how to deal with other JSON type...
At this point I am convinced DRF is a dead project
no. it has 4 new more maintainers now. btw would love to see a failing test case to find out the fix for the problem. who is up for that? here is a comment pointing to the direction https://github.com/encode/django-rest-framework/pull/1671#issuecomment-62003465