How to post a django request to external server - python

Hi so I have this method in django views to post the file to a different server. I get an HTTP 415 error complaining about the media type of the request. I have debugged the request and copied and pasted its contents in fiddler. When I posted the same from fiddler it worked. So I don't understand why it does not work using python requests package.
Can anyone help me with this?
Thanks.
def upload(request):
if request.method == 'POST':
url=settings.WEBSERVICES_URL+'validate'
r = requests.post('http://localhost:9090/validate',data=request)
r2 = requests.get('http://localhost:9090/test')
return render_to_response("upload.html", context_instance=RequestContext(request))
else:
return render_to_response("upload.html", context_instance=RequestContext(request))

Do this:
r = requests.post('http://localhost:9090/validate', data=request.POST)
You are passing a full django.http.HttpRequest object to requests.post, when you only need its post data.

If you look at the documentation of requests it says about the data keyword:
data – (optional) Dictionary, bytes, or file-like object to send in the body of the Request.
Django's request object is an instance of HttpRequest.You should try to put the necessary data in a dictionary and pass it to post().

Related

Enabling CSRF for Django

I have the following python code in my Django views.py, the code takes in a JSON body and send the extracted DATA to another API endpoint, I have simplified the code here.
How do I enable csrf such that it will send the token back to the caller for this method? I am calling this from postman.
#csrf_protect
def validate_booking(request):
if request.method != "POST":
return HttpResponseServerError("Invalid HTTP method")
body = json.loads(request.body)
booking_details = body["booking_details"]
DATA = {
"name": booking_details["name"],
"nric": booking_details["nric"],
"booking_id": booking_details["booking_id"]
}
return HttpResponse(status="200")
This site directs to put this piece of code in my method. But what is "a_template.html"?
https://docs.djangoproject.com/en/4.1/ref/csrf/
#csrf_protect
def my_view(request):
c = {}
# ...
return render(request, "a_template.html", c)
This isn't an easy thing to do as CSRF is 2 steps thing
There is a value that is passed to the client and it is saved to the session on the server.
When a POST request is received, the client shall send this as csrfmiddlewaretoken in the body and the server will check the value against the stored one in the server's session.
So this isn't feasible to be done in APIs as you require session Management which is not of REST API implementations.
Thanks for your reply. I managed to find a solution by doing the following:
Create a new GET method that will generate the session CSRF token using python
Instead of using render which expects a HTML template file, I used JsonResponse(data) to return in JSON format directly
In my postman app which I am making the POST request with the X-CSRFToken in the header, I will first make a GET request to the new method I created in step 1 to retrieve the token and store it as an environment variable
The following is the GET method sample:
from django.http import JsonResponse
def get_csrf_token(request):
csrf_token = csrf(request)['csrf_token']
data = {'csrf_token': csrf_token}
return JsonResponse(data)

Flask WTForms - Retrieve form data when submitting to a different route, i.e. a different POST route than the GET route which renders the form

I would like to set up my URLs/endpoints according to REST as closely as possible, while still utilising Flask-WTForms.
I would like my form to render at GET /posts/new, and submit to POST /post.
With Flask-WTForms I can only work out how to get it to GET/POST to the same URL.
My current code looks like this:
#post_bp.route('/posts/new', methods=['GET', 'POST'])
def show_post_form():
create_post_form = CreatePostForm()
if create_post_form.validate_on_submit():
return 'success'
return render_template('create_post_form.html', form=create_post_form)
However I would like to be able to make it look something more like this, but I just can't seem to work it out:
#post_bp.route('/posts/new', methods=['GET'])
def show_post_form():
create_post_form = CreatePostForm()
return render_template('create_post_form.html', form=create_post_form)
this route only shows the form
the form submits a POST request to /post
<form action="{{url_for('shipment.C_shipment')}}" method="POST" novalidate>
the POST /post route handles the submitted form and if there are errors for example, then it redirects back to GET /posts/new:
#post_bp.route('/post', methods=['POST'])
def create_post():
create_post_form = CreatePostForm()
if create_post_form.validate_on_submit():
return "success!"
if len(create_post_form.errors) != 0:
for error in create_shipment_form.errors:
for msg in create_shipment_form.errors[error]:
flash(msg)
return redirect(url_for('shipment.show_create_shipment_form'))
i guess creating a new CreatePostForm() object here doesn't really work..
Any suggestions?
Creating a new CreatePostForm is correct as it parses the submitted form data for you. This allows you to call validate_on_submit() on the form object.
I don't think you're generating the correct URL for the form action in your HTML snippet. The argument to url_for() should be the desired endpoint (see docs) which should be <post_bp>.create_post. This would be similar to your call
return redirect(url_for('shipment.show_create_shipment_form'))
If this does not fix the issue, please provide both frontend and backend error messages you receive when trying to send the data to /post.

Looking for Django equivalent of Flask's request.get_data() (for Slack request verification with raw request body) [duplicate]

Since Django 1.5 raw post data is accessible via request.body.
In my application I sometimes get data send via a form and sometimes raw data (json for example).
Is there any way to write a function like this that does not fail?
def get_post_var(request, name):
result = request.POST.get(name)
if result:
return result
post_body = dict(urlparse.parse_qsl(request.body))
result = post_body.get(name)
if result:
return result
return None
Use request.data instead of request.body.
request.data does not read the data stream again.
The error You cannot access body after reading from request's data stream will be triggered on a request if (1) that request method is POST, (2) that request's POST dictionary is accessed in middleware, in either process_request or process_view and (3) within the view function, request.body is accessed. It is on (3) that the error will be raised, even though the real cause of the bug is (2).
In order to resolve the error, you need to examine your middleware for where it accesses request.POST and modify it such that it doesn't access request.POST anymore.
The Django docs say that middleware should not access request.POST, and this is one consequence of ignoring that recommendation.
Also check out this Django ticket on the issue, which includes the note:
[M]iddleware that hits request.POST should (usually) be considered a
bug. It means that the view will be unable to set any custom upload
handlers, perform custom parsing of the request body, or enforce
permission checks prior to file uploads being accepted.
Adding to Adam Easterling's answer it is worth noting that Django itself 'violates' the hint of not using request.POST in middleware:
The CsrfViewMiddleware class can be considered an exception, as it
provides the csrf_exempt() and csrf_protect() decorators which allow
views to explicitly control at what point the CSRF validation should
occur.
Which does not sanitilize the violation IMO
For those interested to know, I faced this issue:
You cannot access body after reading from request's data stream
when I added 'oauth2_provider.contrib.rest_framework.OAuth2Authentication'
in the "REST_FRAMEWORK" like so in the settings.py:
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
...
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
...
),
Of course disabling this will work but not a workaround I would be proud of.
I was able to read my request.POST after putting #csrf_exempt before my view function. Because CSRF middleware accesses POST data.
I found a trick, using for my middleware,
request._read_started = False
after doing that, ready body again and it works.
For those with the same error who are not readying the body or POST, I had this same error when I used this line of code in a process_view middleware::
event = request.event if 'event' in request else None
Solved by settings request.event = None at the top of the function so I could then use:
event = request.event

Post data in djangon api and unable to get variable value

I have created a api which i am sending request by post but didn't get vairable in a view
def login_list(request):
if request.method == 'POST':
data = json.dumps(request.POST)
print(data)
serializer = LoginSerializer(data=request.data)
#print(serializer)
return JsonResponse({"message":'fdsafdsa'})
when i print data print(data) then out put is coming like this
{"{\"login\":122122,\"abvc\":\"544545\"}": ""}
and i calling this api like this in postman
Post http://localhost:8000/login/login/
{"login":122122,"abvc":"544545"}
I am not geting value with this
print(request.POST['login']);
how can i get value
Try request.data instead of request.POST. JSON Content is sent in body, which is parsed by Django Rest Framework at runtime.
login_variable = request.data['login']
And ensure you have added 'JSONParser' in REST_FRAMEWORK settings.

Should I use GET or POST to retrieve results Django

I'm using Django and have a view to get/insert some records in database. Here's my code:
class JSONResponse(HttpResponse):
"""
An HttpResponse that renders its content into JSON.
"""
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
#api_view(('GET','POST'))
#renderer_classes((TemplateHTMLRenderer,))
#csrf_exempt
def cours_list(request):
if request.method == 'GET':
data = JSONParser().parse(request)
results = Lesson.objects.get(discipline=data.discipline)
return Response({'cours': results}, template_name='search_results.html')
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = LessonSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JSONResponse(serializer.data, status=201)
return JSONResponse(serializer.errors, status=400)
So to get data I use GET and to insert a new record I use POST. First, is this the right way to do ? I read once that it't a bad idea to use GET whatever the situation.
Also, the GET code is not actually working (I'm getting a bad request error) and it seems that this is comming from JSONParser that is not able to parse the request.
Edit1
Here is the request that is sent:
GET http://127.0.0.1:8000/cours/?{%22discipline%22:%22Mathematiques%22,%22localisation%22:%22%22}
Edit2
I tried to print requet.GET, and this what it gives:
<QueryDict: {'{"discipline":"Mathematiques","localisation":""}': ['']}>
When trying to access request.data['discipline'], it says:
django.utils.datastructures.MultiValueDictKeyError: "'discipline'"
Should I use GET or POST to retrieve results Django
To retrieve use a GET
I read once that it't a bad idea to use GET whatever the situation
Not at all, as long as your GET operation contains no side effects (e.g. in your GET method you are only reading from the database.
The GET code is not actually working (I'm getting a bad request error)
data2 = JSONParser().parse(request) # you used data2
results = Lesson.objects.get(discipline=data.discipline) # and you used data
^
|____ data? data2?
You're not passing the GET parameters correctly
You need to pass GET params like this url/?param1=value1
To read that value you use param1 = request.GET['param1'] and param1 will be the string value1
What you are doing isn't passing a value:
GET http://127.0.0.1:8000/cours/?{%22discipline%22:%22Mathematiques%22,%22localisation%22:%22%22}
That's why you get an empty value ['']
<QueryDict: {'{"discipline":"Mathematiques","localisation":""}': ['']}>
You can pass the entire data as a JSON string if you want, but I prefer to break it down like this:
url/?discipline=Mathematiques&localisation=Quelquechose
with
discipline = request.GET['discipline']
localisation = request.GET['localisation']
That's absolutely normally to use GET method for information retrieving, see HTTP/1.1: Method Dediniton, 9.3:
The GET method means retrieve whatever information (in the form of an
entity) is identified by the Request-URI. If the Request-URI refers to
a data-producing process, it is the produced data which shall be
returned as the entity in the response and not the source text of the
process, unless that text happens to be the output of the process.
For POST method, it's a good practice to submit new data with POST request, see HTTP/1.1: Method Dediniton, 9.5:
The POST method is used to request that the origin server accept the
entity enclosed in the request as a new subordinate of the resource
identified by the Request-URI in the Request-Line. POST is designed to
allow a uniform method to cover the following functions:
................................................................
- Providing a block of data, such as the result of submitting a
form, to a data-handling process;
- Extending a database through an append operation.
Also, take a look at Which HTTP methods match up to which CRUD methods? it will give you more clear idea of how and when particular HTTP methods shall be used and help you in next further development.

Categories