Body in Request ignored when forming POST dict in Django - python
I am working on a Django server that takes an integer from POST data. If I send the integer via GET there's no problems, but it gets dropped when sent via POST.
I run the server with:
./manage.py runserver 0.0.0.0:8000
and then generate the POST request with:
curl -X POST -H "Content-Type: application/json" -d '{"myInt":4}' "http://0.0.0.0:8000/myURL/"
I am using PDB in the view, and here is the result I am getting for the following commands:
request.method
> 'POST'
request.body
> '{"myInt":4}'
request.POST
> <QueryDict: {}>
I have used #csrf_exempt as a decorator for the view, just to make sure that isn't causing any problems.
Currently it is baffling me that request.POST does not contain myInt, is my POST request not well-formed?
Your post request is sending JSON not application/x-www-form-urlencoded
If you look at the django docs about HttpRequest.POST .
A dictionary-like object containing all given HTTP POST parameters, providing that the request contains form data. See the QueryDict documentation below. If you need to access raw or non-form data posted in the request, access this through the HttpRequest.body attribute instead.
You need to POST form encoded data. I didn't test this and haven't used curl in a while, but I believe the following should work.
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "myInt=4" "http://0.0.0.0:8000/myURL/"
Related
How to specify Accept headers from rest_framework.test.Client?
I'm trying to set up an API endpoint to reply with HTML or JSON depending on the incoming request's Accept headers. I've got it working, testing through curl: > curl --no-proxy localhost -H "Accept: application/json" -X GET http://localhost:8000/feedback/ {"message":"feedback Hello, world!"} > curl --no-proxy localhost -H "Accept: text/html" -X GET http://localhost:8000/feedback/ <html><body> <h1>Root</h1> <h2>feedback Hello, world!</h2> </body></html> I can't figure out how to use the APITestCase().self.client to specify what content should be accepted, though. My view looks like class Root(APIView): renderer_classes = (TemplateHTMLRenderer,JSONRenderer) template_name="feedback/root.html" def get(self,request,format=None): data={"message": "feedback Hello, world!"} return Response(data) and my test code looks like class RootTests(APITestCase): def test_can_get_json(self): response = self.client.get('/feedback/',format='json',Accept='application/json') self.assertEqual(response.status_code, 200) self.assertEqual(response.accepted_media_type,'application/json') js=response.json() self.assertIn('message', js) self.assertEqual(js['message'],'feedback Hello, world!') which dies on the test for response.accepted_media_type. What's the right way to do this? All I can find says that the format argument should be sufficient.
As was rightfully stated here, the docs don't seem to say much about how to add headers to the request using the test client. However, the extra parameter can be used for that but the trick is that you have to write it the exact way the http header looks. So you should do this: self.client.get('/feedback/', HTTP_ACCEPT='application/json')
django rest framework 3.8.2 - getting data from request.data (POST)
I'm having troubles on retrieving data on posting a request: curl 'http://127.0.0.1:8005/api/curricula_report/v1/report-data/?format=json' --data-binary '{"storesIds":[80403,66729,66996,67355,67393,67405,67406,67417,67439,67690,67713,67780,67851,68060,68082,68224,68305,68338,68414,68422,68437,68508,68513,68542,69004,69131,69516,69693,69845,69886,69887,69890,69954,69960,69976,70025,70102,70151,70166,70273,70334,70493,70512,70632,70696,70864,70991,71099,71415,71551,71572,71693,71926,71979,72478,72830,72846,72848,72872,72881,73202,73253,73326,73337,73363,73364,73382,73452,73463,73674,73683,73776,78997,73909,74666,73921,73989,77485,77538,77843,78135,77902,77833,78961,79238,80106,79239,79785,80914,81129,80800,81115,80520,80521,80801,81825,81659,82441,83128,74489],"courseIds":["3f8c8bd7-5aae-4184-a824-68edf528a011"],"audienceId":2,"hiredId":1,"user":"TW9oYW1tYWQ7UmhhbWFuO21vaGFtbWFkcmhhbWFuO21vaGFtbWFkcmhhbWFuO21vaGFtbWFkQGRla2tncm91cC5jb207ZHVua2luYnJhbmRzOzIwMTgtMDctMDNUMTE6MjE6MzhaO0M3RDVCMUZEOUExN0RFNDEyNUVDODJBRTEzOTFEQ0E5N0M4Q0VFNUM"}' --compressed on inspecting the request through ipdb: def post(self, request, *args, **kwargs): post_data_dict = request.data user_token = post_data_dict.get('user', None) user is always None. ipdb> post_data_dict <QueryDict: {u'{"storesIds":[80403,66729,66996,67355,67393,67405,67406,67417,67439,67690,67713,67780,67851,68060,68082,68224,68305,68338,68414,68422,68437,68508,68513,68542,69004,69131,69516,69693,69845,69886,69887,69890,69954,69960,69976,70025,70102,70151,70166,70273,70334,70493,70512,70632,70696,70864,70991,71099,71415,71551,71572,71693,71926,71979,72478,72830,72846,72848,72872,72881,73202,73253,73326,73337,73363,73364,73382,73452,73463,73674,73683,73776,78997,73909,74666,73921,73989,77485,77538,77843,78135,77902,77833,78961,79238,80106,79239,79785,80914,81129,80800,81115,80520,80521,80801,81825,81659,82441,83128,74489],"courseIds":["3f8c8bd7-5aae-4184-a824-68edf528a011"],"audienceId":2,"hiredId":1,"user":"TW9oYW1tYWQ7UmhhbWFuO21vaGFtbWFkcmhhbWFuO21vaGFtbWFkcmhhbWFuO21vaGFtbWFkQGRla2tncm91cC5jb207ZHVua2luYnJhbmRzOzIwMTgtMDctMDNUMTE6MjE6MzhaO0M3RDVCMUZEOUExN0RFNDEyNUVDODJBRTEzOTFEQ0E5N0M4Q0VFNUM"}': [u'']}> not sure what I'm doing wrong, all the keys seems to be omitted, and the values too: ipdb> post_data_dict.keys() [u'{"storesIds":[80403,66729,66996,67355,67393,67405,67406,67417,67439,67690,67713,67780,67851,68060,68082,68224,68305,68338,68414,68422,68437,68508,68513,68542,69004,69131,69516,69693,69845,69886,69887,69890,69954,69960,69976,70025,70102,70151,70166,70273,70334,70493,70512,70632,70696,70864,70991,71099,71415,71551,71572,71693,71926,71979,72478,72830,72846,72848,72872,72881,73202,73253,73326,73337,73363,73364,73382,73452,73463,73674,73683,73776,78997,73909,74666,73921,73989,77485,77538,77843,78135,77902,77833,78961,79238,80106,79239,79785,80914,81129,80800,81115,80520,80521,80801,81825,81659,82441,83128,74489],"courseIds":["3f8c8bd7-5aae-4184-a824-68edf528a011"],"audienceId":2,"hiredId":1,"user":"TW9oYW1tYWQ7UmhhbWFuO21vaGFtbWFkcmhhbWFuO21vaGFtbWFkcmhhbWFuO21vaGFtbWFkQGRla2tncm91cC5jb207ZHVua2luYnJhbmRzOzIwMTgtMDctMDNUMTE6MjE6MzhaO0M3RDVCMUZEOUExN0RFNDEyNUVDODJBRTEzOTFEQ0E5N0M4Q0VFNUM"}'] ipdb> post_data_dict.values() [u''] with rest_framework v 3.1.3 it was working. any help on this?
I had similar issue few weeks ago. The problem is with the content-type of the request which in your case is application/x-www-form-urlencoded This for some reason causing the problem which you experience. If you explicitly set the content type of your request to application/json, the input is processed as you'd expect: curl -H "Content-Type: application/json" ....
Django DRF JWT authentication get token - JSON parse error - Expecting value
I have simple Django DRF application setup which I have implemented JWT authentication. I used the Django REST framework JWT documentation I am using curl to test the implementation. I can successfully get a token using the following notation used in the documentation: $ curl -X POST -d "username=admin&password=password123" http://localhost:8000/api-token-auth/ The token is returned in following format: {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InNpdHJ1Y3AiLCJleHAiOjE1MTE2NTEyMTQsInVzZXJfaWQiOjEsImVtYWlsIjoiY3VydGlzLnBva3JhbnRAZ21haWwuY29tIn0.F1TSkxe5tQVpddetUdOJDdAPP1XB9Bimb5U3c75oWd0"} However, when I try using this other variation, I get an error: $ curl -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"password123"}' http://localhost:8000/api-token-auth/ The error I get is: {"detail":"JSON parse error - Expecting value: line 1 column 1 (char 0)"} I also had the same error when trying to refresh or verify the token: Refresh: $ curl -X POST -H "Content-Type: application/json" -d '{"token":"<EXISTING_TOKEN>"}' http://localhost:8000/api-token-refresh/ Verify: $ curl -X POST -H "Content-Type: application/json" -d '{"token":"<EXISTING_TOKEN>"}' http://localhost:8000/api-token-verify/ I was adding the token as follows: curl -X POST -H "Content-Type: application/json" -d '{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InNpdHJ1Y3AiLCJleHAiOjE1MTE2NDg5MjIsInVzZXJfaWQiOjEsImVtYWlsIjoiY3VydGlzLnBva3JhbnRAZ21haWwuY29tIn0.T5h_PSvzvKOZCPTS60x5IUm3DgAsRCRmbMJeGWZk3Tw"}' http://localhost:8800/api-token-refresh/ Am I perhaps adding the token incorrectly? Does it need some other formatting with quotes?
Those requests are sending data in two different ways. The first request sends it as form data (x-www-form-urlencoded) which is what your endpoint is expecting and the second request sends it as application/json. I'm not sure that the library you're using will handle a json request out of the box so one option would be to create a custom endpoint and use something like the following: import json def ParseFormData(self, request): payload = json.loads(request.body.decode('utf-8')) // use django auth to authorize request and return token You can read more about it in this answer here: https://stackoverflow.com/a/29514222/5443056 There's instructions for manually creating auth tokens in your library's documentation. Here's the code: from rest_framework_jwt.settings import api_settings jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER payload = jwt_payload_handler(user) token = jwt_encode_handler(payload)
i suggest use json.dumps({key:value})
Django JWT Auth, why one request works and the other not
I was trying Django JWT Auth and noticed that the URL responds well to one type of post but doesn't respond well to another, but i can figure out why. Basically, if i use the cURL POST referred in the readme.md, everything goes accordingly to planned: $ curl -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"abc123"}' http://localhost:8000/api-token-auth/ but if you i use another type of cURL POST with the same info, it doesn't work: $ curl -d 'username=admin&password=abc123' http://localhost:8000/api-token-auth/ I know that the "Content-Type" is diferent, but shouldn't the request be accepted in the same manner, they are both well formed posts?
Curl's -d option actually sends the request like it's a web browser. My guess is that the URL you're testing against doesn't have a standard web form, so it can't actually process the request. TL;DR Pretty sure Django JWT Auth doesn't support the application/x-www-form-urlencoded content type. From curl manual: -d --data (HTTP) Sends the specified data in a POST request to the HTTP server, in the same way that a browser does when a user has filled in an HTML form and presses the submit button. This will cause curl to pass the data to the server using the content-type application/x-www-form-urlencoded. Compare to -F, --form. Hope this helps!
"CSRF token missing" when using curl with a Flask app
I am trying to submit a form on a Flask app using curl. Unfortunately, I keep running into the "CSRF token missing" error. I tried: curl -X POST --form csrf_token=token --form data=#file.txt --form submit=submit {url} -v I used a csrf_token from the app while I had it open in a browser. I also looked at https://flask-wtf.readthedocs.org/en/latest/csrf.html and tried to set X-CSRFToken in the header but still got the same error. Any suggestions for what is the correct way to use curl to feed the token to the flask app?
The problem is that you just sending token and flask cannot get your session which lives in browser cookie. So if you wish to access your view via curl it's not enough to pass token value within POST request, you have to attach cookie to. You can write cookie to local file with command: curl -c /path/to/cookiefile {url} Then modify it and send POST request to your server with attached cookie and token: curl -b /path/to/cookiefile -X POST --form csrf_token=token --form data=#file.txt --form submit=submit {url} -v