django - post data query dict is empty - python

i use postman app and set content-type : application/json
and using post method
in the body i select "raw" and "JSON(application/json)"
and after all of this i enter a simple json :
{"token":"ghdfhldfigpd","text":"test Expense" ,"amount":10000}
but when i debug my django app : query dict is empty see this picture
but when i enter my data in form-data section
my app works and post query dict is not empty
what the problem should be ?
EDIT : i see that the data goes to body but not to post query dict:
this picture

request.POST is only for application/x-www-form-urlencoded data. Since you are using json, you should use request.body with json.loads.
import json
def my_view(request):
data = json.loads(request.body.decode('utf-8'))
...

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)

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.

Serializing optionally nested structures: Difference between QueryDict and normal dict?

I'm running into weird behavior when writing nested structures with django-rest and then trying to test them using django-rest's test client. The nested child object should be optional.
Here's a sample serializer:
from rest_framework import serializers
class OptionalChildSerializer(serializers.Serializer):
field_b = serializers.IntegerField()
field_c = serializers.IntegerField()
class Meta:
fields = ('field_b', 'field_c', )
class ParentSerializer(serializers.Serializer):
field_a = serializers.IntegerField()
child = OptionalChildSerializer(required=False, many=False)
class Meta:
fields = ('a', 'child',)
def perform_create(self, serializer):
# TODO: create nested object.
pass
(I've omitted the code in perform_create, as it's not relevant to the question).
Now, passing a normal dict as data argument works just fine:
ser = ParentSerializer(data=dict(field_a=3))
ser.is_valid(raise_exception=True)
But passing a QueryDict instead will fail:
from django.http import QueryDict
ser = ParentSerializer(data=QueryDict("field_a=3"))
ser.is_valid(raise_exception=True)
ValidationError: {'child': {'field_b': [u'This field is required.'], 'field_c': [u'This field is required.']}}
On the actual web site, the API gets a normal dict and thus works fine. During testing however, using something like client.post('url', data=dict(field_a=3)) will result in a QueryDict being passed to the view, and hence not work.
So my question is: what's the difference between the QueryDict and normal dict? Or am I approaching this the wrong way?
DRF defines multiple parser classes for parsing the request content having different media types.
request.data will normally be a QueryDict or a normal dictionary depending on the parser used to parse the request content.
JSONParser:
It parses the JSON request content i.e. content with .media_type as application/json.
FormParser
It parses the HTML form content. Here, request.data is populated with a QueryDict of data. These have .media_type as application/x-www-form-urlencoded.
MultiPartParser
It parses multipart HTML form content, which supports file uploads. Here also, both request.data is populated with a QueryDict. These have
.media_type as multipart/form-data.
FileUploadParser
It parses raw file upload content. The request.data property is a dictionary with a single key file containing the uploaded file.
How does DRF determines the parser?
When DRF accesses the request.data, it examines the Content-Type header on the incoming request and then determines which parser to use to parse the request content.
You will need to set the Content-Type header when sending the data otherwise it will use either a multipart or a form parser to parse the request content and give you a QueryDict in request.data instead of a dictionary.
As per DRF docs,
If you don't set the content type, most clients will default to using
'application/x-www-form-urlencoded', which may not be what you wanted.
So when sending json encoded data, also set the Content-Type header to application/json and then it will work as expected.
Why request.data is sometimes QueryDict and sometimes dict?
This is done because different encodings have different datastructures and properties.
For example, form data is an encoding that supports multiple keys of the same value, whereas json does not support that.
Also in case of JSON data, request.DATA might not be a dict at all, it could be a list or any of the other json primitives.
Check out this Google Groups thread about the same.
What you need to do?
You can add format='json' in the tests when POSTing the data which will set the content-type as well as serialize the data correctly.
client.post('url', format='json', data=dict(field_a=3))
You can also send JSON-encoded content with content-type argument.
client.post('url', json.dumps(dict(field_a=3)), content_type='application/json')
The django-rest test client doesn't automatically serialize data as json, but uses multipart/form, which results in a QueryDict.
There is, however, a format option, described in the docs. The following test code works fine:
client.post('url', format='json', data=dict(field_a=3))
I'm still puzzled on the different serializer behavior between a normal dict and a QueryDict, though...
Thanks Rajesh for pointing me in the right direction!

How to get POST data from request?

I just set up an apache server with django, and to test it, made a very simple function in views.py
channel = rabbit_connection()
#csrf_protect
#csrf_exempt
def index(request):
data={'text': 'Food truck is awesome! ', 'email': 'bob#yahoo.com', 'name': 'Bob'}
callback(json.dumps(data))
context = RequestContext(request)
return render_to_response('index.html', context_instance=context)
This function works fine if I send a GET or POST request to the server. However I would like to get this data from POST request. Assuming I send request like this:
import pycurl
import simplejson as json
data = json.dumps({'name':'Bob', 'email':'bob#yahoo.com', 'text': u"Food truck is awesome!"})
c = pycurl.Curl()
c.setopt(c.URL, 'http://ec2-54-......compute-1.amazonaws.com/index.html')
c.setopt(c.POSTFIELDS, data)
c.setopt(c.VERBOSE, True)
for i in range(100):
c.perform()
What I would like to have in the view is something like this:
if request.method == 'POST':
data = ?????? # Something that will return me my dictionary
Just in case:
It is always will be in JSON format and the fields are unknown.
data= request.POST.get('data','')
Will return you a single value (key=data) from your dictionary. If you want the entire dictionary, you simply use request.POST. You are using the QueryDict class here:
In an HttpRequest object, the GET and POST attributes are instances of django.http.QueryDict. QueryDict is a dictionary-like class customized to deal with multiple values for the same key. This is necessary because some HTML form elements, notably , pass multiple values for the same key.
QueryDict instances are immutable, unless you create a copy() of them. That means you can’t change attributes of request.POST and request.GET directly.
-Django Docs
If the data posted is in JSON format, you need to deserialize it:
import simplejson
myDict = simplejson.loads(request.POST.get('data'))

How to post a django request to external server

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().

Categories