Using a simple Python script, i want to send a request, with Python-Requests, to a Django view. The Django view should receive the json data inside the request and should print it to my console; here is what i tried:
This is how i send the request:
url = 'http://127.0.0.1:8000/myview/view'
client = requests.session()
csrftoken = requests.get(url).cookies['csrftoken']
data = json.dumps({'data': 'test-value'})
header = {'X-CSRFToken': csrftoken}
cookies = {'csrftoken': csrftoken}
resp = requests.post(url, data=data, headers=header, cookies=cookies)
And this is how the Django view receives it:
def myview(request):
if request.method == 'POST':
data = request.POST.get('data')
print(data)
print('received.')
response = HttpResponse(get_token(request))
return response
The problem with my current code is that print(data) will throw the following output:
None
received.
[06/Jan/2020 21:23:57] "POST /myview/view HTTP/1.1" 200 64
So, instead of printing test-value, it prints nothing. I don't understand whether the error is in my Django view or in how i'm sending the request. Any advice is appreciated!
The problem is with your request, and entirely caused by this line:
data = json.dumps({'data': 'test-value'})
You simply want
data = {'data': 'test-value'}
The POST data should be sent as a simple dictionary, not a JSON string - see the documentation and example here.
Related
I am trying to send data from localhost to an API in remote server using Python Requests & Django through an API: /api/send-data/
Path for /api/send-data/ in urls.py is path('send-data/',view_send_data.send_data,name='send_data')
This is my view_send_data.py in my localhost:
#api_view(('POST',))
#renderer_classes((TemplateHTMLRenderer, JSONRenderer))
def send_data():
# defining the API-endpoint
API_ENDPOINT = "http://68.183.89.234/api/screen/"
# data to be sent to API
data = {'data':1234}
# sending post request and saving response as response object
r = requests.post(url = API_ENDPOINT, data = data)
print(r.json())
return Response({"success": True}, status=status.HTTP_200_OK)
Path for api at http://68.183.89.234/api/screen/ in urls.py is path('screen/',views_fr.screen_display,name='screen')
This is my views_fr.py in my remote server:
#api_view(['POST'])
def screen_display(request):
if request.method == 'POST':
return Response({"success": True,
"response": request.data}, status=status.HTTP_200_OK)
When I call "http://127.0.0.1:8000/api/send-data/" in my browser, I am getting 405 Method Not Allowed
Is this the correct way to do it or am I missing something? Thank you.
The error you are getting is because the remote server API only accepts POST method, but you can't make a POST request using the browser url call. Test the API using postman or curl so you can set the correct method for request.
I'm trying to create a simple microservice structure on my Django projecjt: so when a certain Django view is called, this view will send a JSON post request to a Flask microservice containing some user's data; the Flask microservice should receive the request, take that user's data and send back to Django some additional data using Requests again, so that my Django view can receive that data and perform some operations, such as showing it to the user.
Right now i'm just sending some dummy data, to test if this whole system ( Django > request to Flask > Flask > Request to Django) works, but i'm having some problems.
To debug my code, i'm trying to just print the received data. Here is my view:
def myView(request):
mydict = {}
# The request is sent to my external Python script..
req = requests.post('http://127.0.0.1:5000/', json={"one": 1}) # Some dummy data
# .. Once the external script sends back a request with data, this should handle it
if request.method == 'POST':
# The data is inside this variable
data = request.POST
for key in data.items():
if float(key[1]) > 0:
mydict.update({key[0]: key[1]})
print(mydict) #FIRST PRINT STATEMENT
print(mydict) #SECOND PRINT STATEMENT
response = HttpResponse(get_token(request))
return JsonResponse(mydict) #RETURNS "{}"
And here is how my Flask app sends data (once it receives the POST request from the Django view) using the Python-Requests library:
#app.route("/", methods=["GET","POST"])
def test():
# After the request from the VIEW is received, a request containing some random json data
# is sent to Django
url = 'http://127.0.0.1:8000/myView/'
client = requests.session()
# We need to get the CSRF token, in order for the request to be taken by Django
csrftoken = requests.get(url).cookies['csrftoken']
data = {"two": 2}
header = {'X-CSRFToken': csrftoken}
cookies = {'csrftoken': csrftoken}
resp = requests.post(url, data=data, headers=header, cookies=cookies)
# Let's seend the request to Django
return f"Test!"
Here is what's wrong with my code:
METHOD: POST
{'two': 2}
[10/Jan/2020 10:41:37] "POST /myView/ HTTP/1.1" 200 320
{}
[10/Jan/2020 10:41:37] "GET /myView/ HTTP/1.1" 200 2
Here is what's wrong:
Why does the first print statement return the correct data and why doesn't the second print? And why does return JsonResponse return an empty dictionary?
I tried to add print('METHOD: ', request.method) in the first lines of the view, here is what happened:
METHOD: GET
METHOD: GET
[10/Jan/2020 10:46:22] "GET /myView/ HTTP/1.1" 200 2
METHOD: POST
[10/Jan/2020 10:46:26] "POST /myView/ HTTP/1.1" 200 320
[10/Jan/2020 10:46:26] "GET /myView/ HTTP/1.1" 200 2
You're flask view can be simplified to just return the required data
#app.route("/", methods=["GET","POST"])
def test():
return {"two": 2}
Then you can use the data in the Django view after you have made the request to flask
response = requests.post('http://127.0.0.1:5000/', json={"one": 1})
print(response.json()) # This should contain the returned data
so I am hosting an image using flask and then I want to do a post request to an API using the url all in the same code:
#app.route('/host')
def host():
return send_from_directory("C:/images", "image1.png")
#app.route('/post')
def post():
response = requests.post(url, data={'input':'<url for host>', headers=headers)
return jsonify(response.json())
I believe as both these view functions are in the same python file, post() gets blocked.
Is there a workaround this problem ?
PS: if I host images on a different machine, it works, but that's not what I desire.
Thanks!
I think there are some problems with your code.
First, I don't believe there is an #app.post() decorator in Flask. My guess is that you were trying to specify that that route should be POSTed to by your users. The way to do that would be #app.route('/post', methods=['POST']).
Next, it seems like you want the /post endpoint to send a POST request to a user-specified(?) URL when the user sends an HTTP request to this endpoint. The way you would do that for a user-specified / user-POSTed URL is something like this (I haven't run this code to test it):
#app.route('/send_post_request', methods=['POST'])
def send_post_request():
user_posted_data = json.loads(request.data)
user_specified_url = user_posted_data['url']
dict_to_post= { 'input': url_for('hosts') }
headers = {} # Fill these in
response = requests.post(user_specified_url , json=dict_to_post, headers=headers)
return jsonify(response.json())
If the URL to send the POST request to is known by the server, you could have your user simply send a GET request:
#app.route('/send_post_request', methods=['GET'])
def send_post_request():
dict_to_post = { 'input': url_for('hosts') }
headers = {} # Fill these in
server_specified_url = '' # Fill this in
response = requests.post(server_specified_url, json=dict_to_post, headers=headers)
return jsonify(response.json())
I have been using this function to handle http requests with no problems:
def do_request(self, method, url, **kwargs):
params = kwargs.get('params', None)
headers = kwargs.get('headers', None)
payload = kwargs.get('data', None)
request_method = {'GET':requests.get, 'POST': requests.post, 'PUT': requests.put, 'DELETE': requests.delete}
request_url = url
req = request_method[method]
try:
res = req(request_url, headers=headers, params=params, data=json.dumps(payload))
except (requests.exceptions.ConnectionError, requests.exceptions.RequestException) as e:
data = {'has_error':True, 'error_message':e.message}
return data
try:
data = res.json()
data.update({'has_error':False, 'error_message':''})
except ValueError as e:
msg = "Cannot read response, %s" %(e.message)
data = {'has_error':True, 'error_message':msg}
if not res.ok:
msg = "Response not ok"
data.update({'has_error':True, 'error_message':msg})
if res.status_code >= 400:
msg = 'Error code: ' + str(res.status_code) + '\n' + data['errorCode']
data.update({'has_error':True, 'error_message': msg})
return data
When I have to do a DELETE request without body entity I have no problems but when I try to add one (when required by the server) I get an error message from the server telling that the body cannot be null as if no body has been sent. Any ideas why this might be happening? I'm using requests module and python 2.7.12. As far as I know data can be send in a DELETE request. Thanks!
There are problems with some clients and some servers when DELETE includes entity body: Is an entity body allowed for an HTTP DELETE request? for example & lots of search results.
Some servers (apparently) convert the DELETE into a POST, others simply perform the DELETE but drop the body. In your case, you've investigated that indeed, the body of a DELETE is dropped by the server & it has been suggested that you change the DELETE to POST.
Mmm... I can send a DELETE with body with Postman and works OK. But I cant get the same result with Requests 2.17.3
This is a issue related to Requests
Part of my Flask code:
#app.route('/api/post', methods=['POST'])
def post():
body = request.get_json()
json_body = json.loads(body)
new_id = mongo.db.Projects.insert(json_body)
return str(new_id)
Script to post a new database entry:
payload = { 'ProjectName' : 'KdB Test Project' }
headers = {'Content-type': 'application/json', 'Accept': 'application/json'}
r = requests.post('http://localhost:5000/api/post', headers=headers, data=json.dumps(payload))
I keep getting json decoder TypeError problems, e.g.
TypeError: expected string or buffer
2016-08-16 15:19:31,388 - werkzeug - INFO - 127.0.0.1 - - [16/Aug/2016 15:19:31] "POST /api/post HTTP/1.1" 500 -
I have tried several things, incl. posting strings. Any clue what is wrong with the way I post a dictionary?
The problem appears to be at the point of body = request.get_json(). I don't think I am picking up any data...
You don't need to loads request message to get dict format. Information stored in body variable is already in dict form. Simply doing the following should remove the error:
#app.route('/api/post', methods=['POST'])
def post():
body = request.get_json()
# json_body = json.loads(body)
new_id = mongo.db.Projects.insert( body )
return str( new_id )
http://flask.pocoo.org/docs/0.11/api/#flask.Request.get_json
get_json is probably returning a dict already, so you don't need to call json.loads(body) (this is what most likely causes the TypeError).
#app.route('/api/post', methods=['POST'])
def post():
json_body = request.get_json()
new_id = mongo.db.Projects.insert(json_body)
return str(new_id)