Issue with django rest framework while handling url-encoded data - django

I am building a REST API server that handles POST requests. The content type in the request is "application/x-www-form-urlencoded".In the request body, we are sending "data1" (some string) and "image" ( a file)
Here's the sample inputForm code I have:
from django import forms
class RequestForm(forms.Form):
data1= forms.CharField(label='data1',max_length=10000)
image = forms.ImageField()
I then validate the content in the form request:
if request.method == 'POST':
form = RequestForm(request.POST)
print("Form content: {0}".format(form))
if form.is_valid():
print("Works")
else:
print("Issue")
Now, when I send the above mentioned data, I always get an error. It prints "Issue". In addition, the line taht prints form content shows it as an error. Something like:
<ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="data1" maxlength="10000"
One interesting point: if I remove "Content-type" from the request header, it works.
Any inputs on how I can read the form data correctly when we use content type as application/x-www-form-urlencoded.
thanks in advance...

As per Django Forms documentation:
By default, each Field class assumes the value is required, so if you pass an empty value – either None or the empty string ("") – then clean() will raise a ValidationError exception
You are on the right track, you should send the form as multipart/form-data as per this thread: Thread about form Content types

Found the solution. To begin with, I am sending a file in the input. So I should use content type as "multipart-formdata".
In addition, I am using Postman to pump in the REST API requests. In the body of the request, I set form-data which automatically sets the headers correctly based on what I am sending in the body. I was trying to override it with my own header which is not right.
When I resent my http POST request with no headers in Postman, it worked. (of course, I did verify the final http request itself and confirmed Postman is setting the header correctly)

Related

How to submit form with input file using ajax

When i send the <input type='file' src='D:/.../image.png'>'s src throught Ajax to views.py in the views the src is not correct, It appears like D:/fakepath/imag.png the fakepath is some security thing made by browser But how I can upload the form's content when I can't get the path of the file input?
First of all you need to set your enctyoe to multipart/form-data
In django you'll find your files under request.FILES, the easiest way to submit the form is to pass the data with js formdata object, it basically takes the entire form and adds it to your ajax request so you can handle it in django like a regular form

How to parse request in django

Hi i am making an webserver , In which I have to hit some request from html page and return the response. The URL which is generated using html is
http://192.168.2.253:8080/searchSMS/?KPImsgId=0&circle=&subId=&startDate=DD-MM-YYYY&endDate=DD-MM-YYYY&Username=ashish
but in the server side I am not able to see the request data. I am using
q = QueryDict(request.body) but it is showing <QueryDict: {}>
How to find the all the parameters coming in request.
In your case you send the data in url so access the data through request.GET as follow:
username = request.GET.get('Username')
start_date = request.GET.get('startDate')
# ... the same for all the other parameter after the `?` marque.
In fact there is a difference between request data, request.body, request.GET and request.POST:
If you are sending POST request to django function view or class based view: you access the request data in request.body or request.POST.
If you are sending POST request to Django REST Framework: you access the data in request.data. You may also find in Internet request.DATA that correct but it's deprecated in the newer version of DRF in favor of request.data.
If you send parameter in the url like in you case, you access the data form request.GET as explained above.

How do you submit a form from Django server side?

I have a form with some paypal fields and other fields specific to my application. I would like to submit the form to my server, have it process some of the fields and then forward it onto the paypal handler url for payment. If I use the following in my server code:
if request.method == 'POST':
// Process some form elements
// Forward on to paypal
return HttpResponseRedirect("https://www.paypal.com/cgi-bin/webscr")
The problem is that the original form does not get posted with the redirect. How can I make this into an HTTP post with the original form so that they are redirected to Paypal and able to login and complete payment?
you can use http.client to make POST requests. Below is a link to the documentation and examples.
http://docs.python.org/3.1/library/http.client.html
I think that also accepts GET requests, meaning that you can pass that form data in the url. So you should be able to do along these lines...
if request.method == 'POST':
// Process some form elements
// Forward on to paypal
return HttpResponseRedirect("https://www.paypal.com/cgi-bin/webscr?%s" % "&".join(["%s=%s" % (key,value) for key,value in request.POST.iteritems()]))

In Django, is it possible to let Django to ignore sending email error report when

the url is starts with? /socket.io/1/websocket/327459101594
Just by searching through the document, seems there's no way to let Django ignore sending email error report based on request URL.
Does any one have any clue?
You can write your own logging handler.
To check the url you could sublcass djangos AdminEmailHandler and extend the emit method to check the url first.
class MyAdminEmailHandler(AdminEmailHandler):
def emit(self, record):
record.request
# request information is available as request property
super(MyAdminEmailHandler, self).emit(record)

Use Django views for handling blobstore uploads

In stead of using the BlobstoreUploadHandler supplied in AppEngine, I'd prefer to use a Django view, so I can keep all the urls and view functions together. However, I can't find out how to get the blob-key of the uploaded file! (like get_uploads() does for the upload handler). I saw that the BlobstoreUploadHandler uses request.params, but I don't think that is available from Django's Request.
def upload_form(request):
upload_url = blobstore.create_upload_url(reverse(upload_blob))
output = '<html><body>'
output += '<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
output += ('''Upload File: <input type="file" name="file"><br> <input type="submit"
name="submit" value="Submit"> </form></body></html>''')
def upload_blob(request):
print request
# How to get the 'blob-key' from request?!
When I examine the request object, all I get is
<WSGIRequest
GET:<QueryDict: {}>,
POST:<QueryDict: {u'submit': [u'Submit']}>
# And COOKIES, META, etcetera
EDIT: Request.FILES
I discovered that some info can be extracted using Request.FILES, which gives:
<MultiValueDict: {u'file': [<InMemoryUploadedFile: my_file (message/external-body)>]}>
However, I assume that the blobstore still handles the file content (is that why it says "content_type=message/external-body"?), so I still need the key somehow. Calling read() gives:
Content-Type: application/octet-stream
MIME-Version: 1.0
Content-Length: 17
Content-MD5: ZmQ3OTJhNjMzNGE0OTAzNGU4NjE5MDNmMGEwNjliMGE=
content-type: application/octet-stream
content-disposition: form-data; name="file"; filename="a1_blob"
X-AppEngine-Upload-Creation: 2012-02-12 22:11:49.643751
So it looks like AppEngine actually replaced the file content by this descriptor, but still, where does AppEngine put the key?
I'm starting to suspect that the blob-key is just lost when not using the webapp framework, since the UploadedFile object has no key() method.
It took me a long time to find, but the content_type: message/external-body requires extra parameters, to find the actual file, in AppEngine's case, this is the blob-key. However, Django doesn't support these extra content_type parameters, so they are indeed lost in the process. There seems to be a patch, but I don't think it's in the AppEngine Django version yet.
https://code.djangoproject.com/ticket/13721
I had the same problem yesterday. Thanks to your post I realizad that the problem was django and his class views. I finally use a code that I have since 2011 and it still works. It does not use BlobstoreUploadHandler, but it gets the blob_infos from the request after automatically upload it to blobstore.
You can use that function in the next way from your callback django function or class (I finally did not try it in a class view from Django but I think it will work. Currently I'm using it in a function view from Django with its request):
media_blobs = get_uploads(request, populate_post=True)
The function is the next:
import cgi
from google.appengine.ext import blobstore
def get_uploads(request, field_name=None, populate_post=False):
"""Get uploads sent to this handler.
Args:
field_name: Only select uploads that were sent as a specific field.
populate_post: Add the non blob fields to request.POST
Returns:
A list of BlobInfo records corresponding to each upload.
Empty list if there are no blob-info records for field_name.
"""
if hasattr(request,'__uploads') == False:
request.META['wsgi.input'].seek(0)
ja = request.META['wsgi.input']
fields = cgi.FieldStorage(request.META['wsgi.input'], environ=request.META)
request.__uploads = {}
if populate_post:
request.POST = {}
for key in fields.keys():
field = fields[key]
if isinstance(field, cgi.FieldStorage) and 'blob-key' in field.type_options:
request.__uploads.setdefault(key, []).append(blobstore.parse_blob_info(field))
elif populate_post:
if isinstance(field, list):
request.POST[key] = [val.value for val in field]
else:
request.POST[key] = field.value
if field_name:
try:
return list(request.__uploads[field_name])
except KeyError:
return []
else:
results = []
for uploads in request.__uploads.itervalues():
results += uploads
return results
The last function is not mine. I do not remember where I got it three or four years ago. But I think it will help someone.
UPDATE:
You also can use a view handler of webapp.WSGIApplication and at the same time use django. This way will allow you to use BlobstoreUploadHandler and BlobstoreDownloadHandler (for video stream as example). You only need to add the view class in main.py and create its handler:
class ServeVideoHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, resource):
...
downloader_handler = webapp.WSGIApplication([('/pathA/pathB/([A-Za-z0-9\-\=_]+)', ServeVideoHandler),], debug=True)
And in app.yaml add the handler before the script main.application that contains your django app.
- url: /pathA/pathB/(.+)
script: main.downloader_handler
The key info isn't directly in the file, it's in file.blobstore_info.key()
post your form containing your image to a url created using blobstore.create_upload_url():
from google.appengine.ext import blobstore
upload_url = blobstore.create_upload_url('/add_image/')
the created url will save the image in the blobstore and redirect the request (with modified file object) to /add_image/
define a url pattern and view for /add_image/ and handle the image:
def add_action_image(request):
image = request.data.get('image')
image_key = image.blobstore_info.key()
... addl' logic to save a record with the image_key...
As you noted, BlobstoreUploadHandler is open source, so you can see the logic they use to parse the key out of the request params. Note that request.params just includes variables from both the query string and the request body (for POST requests). So you might want to start with your djnago request's REQUEST object.