Why does Django return http 200 if form data is invalid? - django

AFAIK Django uses this way to handle forms:
GET: client receives HTML with input elements
user fills out the form
user submits form: http POST
server/Django validates the form. In this case it is invalid
server sends HTML containg the same form and an error message to the user. With http status 200.
Wouldn't it make more sense to use a different http status code if the data is invalid?
PS: I know the Post/Redirect/Get pattern. The question is: "Why 200 if the data is invalid?"

Related

Django CSRF Token present but still getting 403 Forbidden Error

I am trying to set up a Django API that receives POST requests with some JSON data and basically sends emails to a list of recipients. The logic is rather simple:
First I have the view for when I create a blog post. In the template, I include the csrf_token as specified on the Django Documentation. When I hit the submit button, behind the scene the create-post view, in addition to creating the post, makes a request (I am using the requests module) to the API which is charged with sending the emails. This is the piece of logic the sends the request to the API:
data = {
"title": new_post.title,
"summary": new_post.summary,
"link": var["BASE_URL"] + f"blog/post/{new_post.slug}"
}
csrf_token = get_token(request)
# print(csrf_token)
headers = {"X-CSRFToken": csrf_token}
requests.post(var["BASE_URL"] + "_api/send-notification/", json=data, headers=headers)
As you can see I am adding the X-CSRFToken to the headers which I generate through the get_token() method, as per the Django docs. However, the response in the API is a 403 Forbidden status CSRF Token not set.
I have checked the headers in the request and the token is indeed present. In addition, I have been providing other routes to the API and I have been using it for AJAX calls which again is very simple just follow the Django docs and they work perfectly well.
The problem seems to arise when I make the call from within the view, AJAX calls are handle by Javascript static files, and as I said they work fine.
I have thought that Django didn't allow the use of 2 CSRF tokens on the same page (one for the submit form and the other in the view by get_token()), but that's not the problem.
This is typically the error I get:
>>> Forbidden (CSRF cookie not set.): /_api/send-notification/
>>> "POST /_api/send-notification/ HTTP/1.1" 403 2864
I have read several similar questions on SO but they mostly involved using the csrf_exempt decorator, which in my opinion is not really a solution. It just gets rid of the CRSF token usefulness altogether.
Does anyone have any idea what might be causing this problem?
Thanks
Error tries to tell you that you need to add token into cookie storage like that:
cookies = {'csrftoken': csrf_token}
requests.post(var["BASE_URL"] + "_api/send-notification/", json=data, headers=headers, cookies=cookies)

Postman Mock Server matching algorithm logic for request body param form-data

Is there any option to send mock results depends on form data body value in postman?
I am sending some value in the body as form data and I have two example result and now the mock API return only one example I need to get the result based on the form data value from two examples
I have to call 2 Request with different body values(as form-data) and I need to return json array if the values are correct else I need to return a json object I have saved this two result but while I making mock API it is all ways sending now result only there is no changes in url
Is that possible to send response based on form-data in postman mock api?
I have an api example https://api.exmple.com and i am sending post request wit body form-data and filed check:false or check:true and i need to respond two json based on input filed check false or true how to do it?
When we do with get parameter it is working but not working with body form-data
Updates
I added this in header x-mock-match-request-body:true
Post man responding with this error message
{
"error": {
"name": "mockRequestNotFoundError",
"message": "Double check your method and the request path and try again.",
"header": "No matching requests"
}
}
Update I added postman api key but is not working but when i add x-mock-response-name it is working but i need to x-mock-match-request-body only

Missing form data in request

I have following code
class MyClass(restful.Resource):
def get(self):
headers = {'Content-Type': 'text/html'}
return make_response(render_template('myfile.html'),200,headers)
def post(self):
session['CONSUMER_KEY']=request.form.get('consumer_key')
session['CONSUMER_SECRET']=request.form.get('consumer_secret')
render_template('myfile.html')
api.add_resource(MyClass,"/mag/",endpoint="mag")
I have written following test:
def mytest(self):
content_type={"Content-Type": "application / x - www - form - urlencoded","Content-Disposition": "form-data"}
response = self.client.post(
api.url_for(MyClass), data = json.dumps({'consumer_key':'testconsumerkey',
'consumer_secret':'testconsumersecret'}),
headers=content_type
)
The issue is form data is blank and thats the values are not getting set in session. When i debug i see that request.data is populated but request.form is an empty dictionary. Can someone suggest how I can send form data in a post request from a test
EDIT: Environment details
Python 2.7, Flask web framework, self.client is . I am using flask.ext.testing
You seem to be confused as to what the expected format for the post body should be. Should it be JSON data (which is what you send in the test case), or should it be in the application/x-www-form-urlencoded format (which is what you claim to send in the test case, and what the endpoint will read)?
If you wish to receive JSON data, you'll need to change the endpoint to read the data from request.get_json(). You'll also need to use application/json as the Content-Type header in the test case.
If you wish to receive urlencoded post data, then just simplify the test case by removing the Content-Type header and the json.dumps. Just pass the data dict to the data argument.

How to send data as key - value pairs instead of string via POST using XHR

I'm creating two POST calls. One using a django form and one using angular js via a resource xhr.
The angular setup looks like this:
myModule.factory('gridData', function($resource) {
//define resource class
var root = {{ root.pk }};
var csrf = '{{ csrf_token }}';
return $resource('{% url getJSON4SlickGrid root.pk %}:wpID/', {wpID:'#id'},{
get: {method:'GET', params:{}, isArray:true},
update:{method:'POST', headers: {'X-CSRFToken' : csrf }}
});
});
With creating an xhr post request as such:
item.$update();
This post request is send to the server as expected, but when I want to access the QueryDict I cannot access the data passed using:
name = request.POST.get('name', None)
name is always None like this.
The issue behind this is that the QueryDict object is getting parsed quite strange.
print request.POST
<QueryDict: {u'{"name":"name update","schedule":0"}':[u'']}>
Whereas I would have expected this result, which I got when I send the data via a "normal" Post request:
<QueryDict: {u'name': [u'name update'], u'schedule': [u'0']}>
So it seems to be that Django receives something in the POST request which instructs Django to parse the parameters into one string. Any idea how to circumvent this?
Update:
I found this discussion where they say that the issue is if you provide any content type other than MULTIPART_CONTENT the parameters will be parsed into one string. I checked the content-type send with the POST request and it is really set to 'CONTENT_TYPE': 'application/json;charset=UTF-8'. Thus this is likely the issue. Therefore my question is: How can I set the CONTENT_TYPE for a xhr post request created using angular.js resources to MULTIPART_CONTENT?
you could either:
fiddle with the client to send data instead of json
use json.loads(request.raw_post_data).get('name', None) (django < 1.4)
use json.loads(request.body).get('name', None) (django >= 1.4)
The Angular documentation talks about transforming requests and responses
To override these transformation locally, specify transform functions as transformRequest and/or transformResponse properties of the config object. To globally override the default transforms, override the $httpProvider.defaults.transformRequest and $httpProvider.defaults.transformResponse properties of the $httpProvider.
you can find an example here as was previously pointed at.

best way to send a variable along with HttpResponseRedirect

I am reading a djangobook and get questions about HttpResponseRedirect and render_to_response.
suppose I have a contact form, which posts data to confirm view. It goes through all the validation and database stuff. Then, as a usual way, I output the html with
return render_to_response('thank_you.html',
dict(user_code = user_code),
context_instance=RequestContext(request))
However, the book suggested "You should always issue a redirect for successful POST requests." because if the user "Refresh" on a this page, the request will be repeated. I wonder what's the best way to send the user_code along through HttpResponseRedirect to the thank_you.html.
Pass the information in a query string:
thank_you/?user_code=1234
Or use a session variable.
The problem with a query string is that the user can see the data.
When you send a redirect, you are sending the user back a response (a 302 HTTP response) and they are then making an entirely new request to the provided URL. That's a completely new request/response cycle so there is no way to supply data unless you save it in a session variable, cache, cookie etc.
What you can do instead of telling the user to redirect, is to call the view you want to show them yourself from within the same request (i.e. at the point you would issue the redirect) and then you could pass whatever you liked.