Django receiving QueryDict instead of JSON (from jQuery post) - python

I have a Django Rest API on back-end that stores questions and answers. I also have question sessions, it's an array of questions that has to be processed within 1 request.
The problem is, it works well when I send those requests from curl but when I do this via jquery Django receives QueryDict instead of json.
My js:
$.post('http://127.0.0.1:8000/api/sessions/create/', {
questions: JSON.stringify(questions)
})
When I log JSON.stringify(questions) I see it's looking like it has to be:
[{"description":"test5","type":"YESNO","to_close":5,"choices":""},{"description":"test5","type":"YESNO","to_close":5,"choices":""}]
I can even copy and paste it to curl, and it will work:
curl -X POST http://127.0.0.1:8000/api/sessions/create/ -H 'Content-Type: application/json' --data '{"questions":[{"description":"test4","type":"YESNO","to_close":5,"choices":""},{"description":"test3","type":"YESNO","to_close":5,"choices":""}]}'
But when I do via JS, Django receives it this way:
<QueryDict: {'questions': ['[{"description":"test5","type":"YESNO","to_close":5,"choices":""},{"description":"test7","type":"YESNO","to_close":5,"choices":""}]']}>
My post method looks like this:
def post(self, request, **kwargs):
"""Create a session of questions"""
question_data = request.data.pop('questions')
session = QuestionSession.objects.create()
for question in question_data:
Question.objects.create(
description=question['description'],
question_type=question['type'],
answers_to_close=question['to_close'],
question_session=session)
serializer = QuestionSessionSerializer(data=request.data, many=True)
serializer.is_valid()
serializer.save()
return Response({
'status': 'SUCCESS',
'message': 'A new session has been created!'
})
What is wrong? Since I can easily do it via curl, I think the problem is in jquery request.

I was having this exact same issue and what has worked for me was adding , content_type="application/json" inside my post.

Related

Django POST request from Postman

I am currently stuck with POST requests in Django. I am trying to send a POST request from an external applications such as smartphones or Postman (not forms) to the rest framework. Get requests work just fine.
I went through many posts but couldn't resolve my issue. I tried to use request.body but always get an empty response. I used print(response.body) to print the output to the console and only get b'' back.
class anyClass(APIView):
def post(self, request):
print(request.body)
return Response({"id": 'anyClass',
"data": '1234',
})
How would I get the data from my request?
My post request sent with Postman:
http://127.0.0.1:8000/test/v2/Api/anyClass?qrcode=100023&date=2018-11-27&time=08:00:00&value_1=17
You can get the response in request.data:
class anyClass(APIView):
def post(self, request):
print(request.data)
return Response({"id": 'anyClass',
"data": '1234',
})
Please see the documentation for details.
Update
I think you are making wrong kind of usage of postman. Please see the screen shot regarding how to use it:

DRF Response content-type set to None during tests

I'm using Django Rest Framework (version 3.6.2) to create REST API. I've defined my viewset that inherits from GenericViewSet and have overriden retrieve method to implement custom behaviour.
class FooViewSet(viewsets.GenericViewSet):
serializer_class = FooSerializer
def retrieve(self, request, *args, **kwargs):
...
serializer = self.get_serializer(data)
return Response(serializer.data)
I want to have BrowsableAPI while accessing this endpoint from the browser and receive json response when accessing this endpoint e.g. from the code. I've configured DRF with the following settings:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
),
'TEST_REQUEST_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
),
'TEST_REQUEST_DEFAULT_FORMAT':'json'
}
Everything works as expected, I can access the browsable API from the browser and when making request with the Postman tool I get json response. Unfortunately, I can't achieve the same result during tests.
class GetFooDetailViewTest(APITestCase):
def test_get_should_return_json(self):
response = self.client.get(self.VIEW_URL)
self.assertEqual(response.content_type, "application/json")
I expect the response to have content_type set to application/json (this is the header that I can see in the responses from browser and Postman). But this test fails - response.content_type is set to None. While debugging this test, I've discovered that response._headers dictionary looks like this
{
'vary': ('Vary', 'Cookie'),
'x-frame-options': ('X-Frame-Options', 'SAMEORIGIN'),
'content-type': ('Content-Type', 'application/json'),
'allow': ('Allow', 'GET, PUT, DELETE, OPTIONS')
}
So it seems like the correct header is being set, but it's not getting populated to the content_type attribute. Am I missing something?
This is how I test for the content type. In very few cases my code decides the content-type itself, so I to check that I personally did not do something wrong. DRF code is already tested.
self.assertEqual("application/json", resp['Content-Type'])
You just have to rely on DRF doing it right, its not something you can or need to test. For example, you don't test that DRF parsed your json body correctly. The test server isn't exactly like the real one, but its pretty close. For example, you will get real objects out of response.data, not the json encoded/decoded ones.
Check out the LiveServerTestCase if you need it, but it will be slower.
I ran into something similar and this worked for me:
response = self.client.get(self.VIEW_URL, HTTP_ACCEPT='application/json')

Flask coverting to and from JSON

I'm working on a Flask example that takes blog posts and adding them to a database through a RESTful service.
Prior to implementing the RESTful service, I was adding blog posts to a local database by doing the following:
#main.route('/', methods=['GET', 'POST'])
def index():
form = PostForm()
if current_user.can(Permission.WRITE_ARTICLES) and \
form.validate_on_submit():
post = Post(body=form.body.data,
author=current_user._get_current_object())
db.session.add(post)
return redirect(url_for('.index'))
Now that I've gotten to the RESTful service section, the following to_json() and from_json() functions have been to the Post model:
//Convert a post from JSON
//Class Post(db.Model)
def to_json(self):
json_post = {
'url': url_for('api.get_post', id=self.id, _external=True),
'body': self.body,
'body_html': self.body_html,
'timestamp': self.timestamp,
'author': url_for('api.get_user', id=self.author_id,
_external=True),
'comments': url_for('api_get_post_comments', id=self.id,
_external=True),
'comment_count': self.comments.count()
}
return json_post
//Create a blog post from JSON
//Class Post(db.Model)
#staticmethod
def from_json(json_post):
body = json_post.get('body')
if body is None or body == '':
raise ValidationError('post does not have a body')
return Post(body=body)
The following inserts a new blog post in the database:
//POST resource handler for posts
#api.route('/posts/', methods=['POST'])
#permission_required(Permission.WRITE_ARTICLES)
def new_post():
post = Post.from_json(request.json)
post.author = g.current_user
db.session.add(post)
db.session.commit()
return jsonify(post.to_json()), 201, \
{'Location': url_for('api.get_post', id=post.id, _external=True)}
Would really appreciate it if someone could explain how these functions work with each other. My understanding of it all is that a blog post is typed up on a client device and in order to send it to the web service, the to_json function is called to convert the post to JSON. Once the web service receives the JSON version of the blog post, the from_json function is called to convert the JSON post back to its original state. Is that correct?
Edit:
Just re-read the page and I think my understanding was reverse of whats actually happening. In order to get a blog post from the web service, the to_json function is called to convert the data to JSON. Then on the client side, the from_json function is called to convert the data back from JSON.
Your edit is correct. A common response format for a REST API is JSON, which is why the the response is converted "to JSON" when returning.
Also a common header for sending data to a REST API is application/json, which is why the code converts the received data "from JSON".

Flask with Angular: POST form is empty

I'm sending data via AngularJS POST request:
$http.post('/process', { 'uid': uid, 'action': action }).success(function(response) {
console.log(response);
});
And trying to get sended values in Flask
#app.route('/process', methods = ['POST'])
def process():
return json.dumps({ 'data': request.form.get('uid', 'EMPTY') })
And Flask returns back {"data": "EMPTY"} response. request.form is empty. I've tried to get data from request.data, but it's in strange format there.
I'm learning Python and Flask so I want to do this work with native library, without any other packages right now.
get_json() method helps me
#app.route('/process', methods = ['POST'])
def process():
return json.dumps({ 'data': request.get_json().get('uid') })
If you want to get the data via request.form, you need to have angular send it differently. See this question for details: How can I post data as form data instead of a request payload?
Make sure Content-Type is application/json
Here's a tutorial series on using Flask and AngularJS together - http://tutsbucket.com/tutorials/building-a-blog-using-flask-and-angularjs-part-1/
Hope you'll find it useful.

how we can use ajax() in views.py in django? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have little code over here.
Can you please explain me that what that code exactly does in details. please.
In script here is the ajax call:
$.ajax({
url : "{% url 'upload_document' %}",
type: "POST",
data : {csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
title: document.getElementById('title').value,
//document: document: document.getElementById('document'),
},
dataType : "json",
success: function( response ){
if(response == "True"){
// success
}
else {
//append errors
}
}
});
How ajax is works in django and how can we use ajax request in view.
Here my views
views.py
def upload_document(request):
print request.POST
print request.FILES
if request.is_ajax():
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES, user = request.user)
if form.is_valid():
form.save()
return HttpResponse(simplejson.dumps('True'), mimetype = 'application/json' )
else:
errors = form.errors
return HttpResponse(simplejson.dumps(errors), mimetype = 'application/json' )
Thanks in Advance.
In general, $.ajax method sends an asynchronous http request.
You can read about it here.
First argument is url, where we send request.
Second, is request method it may be GET, POST, PUT, DELETE and etc. see wiki
Third argument is key-value dictionary with data, which you use in server-side.
In django, you may access it in request.POST(in case of post request)
Fourth argument is function, which is invoked when server succesfully returns response.
You do not need if statement in this function, because when request fails or server does not give a response, or server returns error(something like 40* code for example) this function will not be invoked.
This function takes one argument with server's response. You need handling this data, for example showing user a message like Invalid data, please correct errors... or Valid data. your request is in process now. and staff like that.
Last argument is data type of servers response. jQuery is smart enough to parse json or html for you, so in this case, response(argument of success function) is pure JS object, deserialized from JSON.
In your server-side(Django views) you must do some validation of request's data. and do something with it. For example, save it to database. When i have to implement ajax form processing i do sumething like this:
if request.method == 'POST':
response = {}
form = UploadForm(request.POST, request.FILES, user = request.user)
if form.is_valid():
form.save()
response['success'] = 1
else:
response['success'] = 0
response['errors'] = dict(form.errors)
return HttpResponse(simplejson.dumps(response), mimetype = 'application/json' )
And on client side, in js something like this
$.post('/url/to/view',
function(json){
if(json['success']){
alert('Yahooo! Successfull request')
}
else{
alert('Oooops. Looks like you send invalid data')
}
}, 'json')
Good luck!

Categories