Upload image from iOS to Django - ios

I need help getting a basic understanding of uploading a file to a Django view via a post request. This is the Django form I'd like to upload the image to:
https://domfa.de/upload_profile/
This is the views.py code for this exact Django view URL:
def profile_picture(request):
if request.POST:
form = UserProfileForm(request.POST, request.FILES)
obj = form.save(commit=False)
obj.user_id = request.user.id
obj.profile_picture = obj.profile_picture
obj.save()
return render_to_response('profile.html', args, RequestContext(request))
else:
formNew = UserProfileForm()
args = {}
args.update(csrf(request))
args['uid'] = request.user.id
args['form'] = formNew
return render_to_response('profile.html', args, RequestContext(request))
And the actual form for this is extremely simple with just a single field for the actual profile picture:
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('profile_picture',)
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
So the Django side works great, I'm always able to upload an image successfully as long as I'm logged in. I'm stuck though however on how to POST an image to this extremely simple Django view, I've already logged in to the Django server as a user using a separate NSUrl request:
UIImage *picture = [UIImage imageNamed:#"myFile.png"];
NSData *imageData = UIImagePNGRepresentation(picture);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:[NSURL
URLWithString:#"https://domfa.de/upload_profile/"]];
[request setHTTPMethod:#"POST"];
[request setValue:#"image/png" forHTTPHeaderField:#"Content-type"];
[request setHTTPBody:imageData];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSLog(#"%#", returnData);
So assuming all the Django code works, which it does, what's wrong with my objective-c code which does the actual image uploading?
And also, how could I get response messages from the server in the NSLog so I could better know why the server won't accept a file POST request?

Getting feedback what is going on when sending a HTTP request from iOS
The problem is that you are not passing in a pointer to a NSURLResponse object which you could examine after the request was made.
NSURLResponse *response;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
Now you can examine the output by looking at the object.
Why is it not uploading?
There are several issues with your approach: You are using django's forms API which is OK, but there are two pitfalls in your code:
CSRF You are not setting the the CSRF value correctly when submitting the form. You can workaround it by first accessing your form with a GET request, just like a browser would do it, then get the CSRF token from the cookies which the server set and then sending a POST request including the retrieved CSRF token. See also CSRF handling in AJAX requests
Data encoding You are not sending form data back to the view, but raw data instead. This will not work this way. You would have to send proper POST form data. You could do it manually or use ASIHTTPRequest which abstracts the cumbersome handling of multipart/form-data.
I would rethink the design decision to use a form to programatically upload a picture. Why not use something more like a REST API for this? There are great frameworks for implementing a clean REST API in django (e.g. http://tastypieapi.org/).
Maybe looking at the API description of Twitter and app.net could help inspiring you how to build this.

Related

iOS sending a POST and GET in the same request

I am successfully posting data as follows:
NSMutableURLRequest *scriptrequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"myurl.com"]];
[scriptrequest setHTTPMethod:#"POST"];
NSString *sendData =[NSString stringWithFormat:#"ID=%#&action=List", ID, nil];
NSData *scriptdata = [sendData dataUsingEncoding:NSUTF8StringEncoding];
[scriptrequest setHTTPBody:scriptdata];
NSError *scripterr;
NSURLResponse *scriptresponse;
NSData *scriptResponseData = [NSURLConnection sendSynchronousRequest:scriptrequest returningResponse:&scriptresponse error:&scripterr];
My question is, is it possible to also attach GET data to the same call?
GET and POST are different types of HTTP Request.
GET Request is majorly used for fetching the web content while POST is for insert/update some content.
So eventually A single HTTP request can only be of one of the following.
Http types include:
GET
HEAD
POST
PUT
DELETE
TRACE
OPTIONS
CONNECT
PATCH
More technical details at Wikipedia:
http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
It looks to me like you are trying to retrieve data from your server, not update. A more typical way to form the request would be to GET http://myurl.com?ID=123&action=List. However, this really depends on how the server code is written.

iOS/Restkit application design

I'm currently developing an application for iOS that is backed by rails. For the communication between iOS and rails i use RESTkit framework since it takes away a lot of work!
I have some doubts on how to manage the code when it starts to grow! How do you design your applications when you use RESTKit? What kind of data layer do you provide to your controllers to perform different actions?
Thanks
I am not aware of what your goal is with the application that your building in.But to start with i suggest you to create your own custom class(for example: Click this link,which indeed accepts the request(might be POST/GET/PUT) that your making and throws you the details in json format.
On the server side,create the REST api(i prefer php) bridge such that you can able to access the server database.
To start with make login authentication test using POST method(i prefer this because its more secured).
After the login page,i assume you want to show the list of data related to rail,then use UITableView/UICollectionView/Custom GridView.It depends on your requirement.And use the asynchronous approach to send the request but below i haven't used that way ;-)
Example: For login authentication
NSString *post =[[NSString alloc] initWithFormat:#"userName=user&password=pwd"];
NSURL *url=[NSURL URLWithString:#"Your URL/authenticate"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];**
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPBody:postData];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if( theConnection )
{
receivedData = [NSMutableData data];
}
else
{
NSLog(#"theConnection is NULL");
}
NOTE: Always try to return the response in json format.
Q: WHY REST-API WITH JSON? WHY NOT SOAP?
==> Many enterprises are creating mobile applications for their internal staff, for their customers, or both. These applications need access to data, business rules, and business processes. For architectural and security reasons these applications are typically built to access remotes services that provide the data and functionality that are required by the users. That's why All of Yahoo's web services use REST.
-FASTER: REST is almost always going to be faster.
-LOW BANDWIDTH: REST is much more lightweight. For mobile devices even with low bandwidth & network, Restful service works well for mobile devices.
-LOW MEMORY CONSUMPTION: The important/must thing in the mobile devices is how we handle the memory when running our application. REST always uses less memory without any unwanted xml strings.
Concerning REST or SOAP, the last one is indeed really heavy for mobile platform and not so easy to implement. SOAP requires XML too and cannot be used with JSON. Whereas with REST you can use JSON or XML and easily implement it on mobiles with RESTKit (http://restkit.org/), for security we can use an SSL connection with HTTPS and a signed certificate.
Source: http://en.wikipedia.org/wiki/Representational_state_transfer
I believe that the information what i have given above is still not enough,you need to do a google a bit.(http://www.restapitutorial.com)
I usually prefer to create a singleton data controller which provides an API in terms of the model objects and the human understandable operation being performed (getPost, addCommentToPost, createPost, ...). This gives one place that controllers go to get data and means I don't need to pass the data controller around. It also means that all of the mappings are in one place and are isolated from the rest of the code (so when the server changes I don't need to change any code in the controllers, just the code which maps into the model objects).

HTTP Post - Time Out - Multiple Request getting initiated within timeout interval

I am using HTTP Post method and initiating a synchronous request.
[NSURLConnection sendSynchronousRequest: ..]
For HTTP POST requests, the default time out is happening at 75 seconds as discussed in many threads.
But during that time out period of 75 seconds, Multiple web service requests are getting initiated for us for the same request raised with all the same parameters.
Please let us know What causes this multiple requests to get initiated? Is this due to HTTP POST in general or because of Synchronous request?
#iOS Sample Code
[body appendData:[[NSString stringWithFormat:#"\r\n--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
[request addValue:[NSString stringWithFormat:#"%d", body.length] forHTTPHeaderField: #"Content-Length"];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
NSURLResponse *response;
response = nil;
urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(urlData)
{
NSString *responseString = [[NSString alloc] initWithData:urlData encoding:NSASCIIStringEncoding];
[self parseStringInformation:responseString infoDict:informationDictionary];
//NSLog(#"%#",responseString);
}
Without the server's request-response logs there are several possibilities.
Programmer Error: Have you already gone through all of "gotchya" type situations?
Have you put a logging message right before your "urlData = [NSURLConnection sendSynchronousRequest: ..." line to make sure your code is only calling it once?
Are you calling this function from within your main GUI thread, if you are that's not supported/recommended, which means it could be causing side-effects like what you're describing. https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html
Are you sure your Request is set up as a POST and has the proper headers like "Content-type: multipart/form-data, boundary=X"
Web Server Responses: Without the web servers logs (or the code for the service your POSTing to) it's hard to say...
Perhaps your server is sending cyclical redirects to the client. If you don't implement a "connection:willSendRequest" then the redirects could be followed for ?X? amount of times for one request. http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/urlloadingsystem/Articles/RequestChanges.html
API Error: You've found some corner case which is causing unwanted side effects. Maybe apple has an bug tracker or developer support forum?
If this is the case you'll have to work around the bug, until it's fixed. I suggest implementing the Asynchronous call chain. "Loading Data Asynchronously" https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html

Google App Engine. Google app engine seeing POST requests as a GET

I'm having the strangest issue right now with google app engine. I'm sending a POST request from iOS and google app engine instead invokes the GET handler.
I've sandboxed this one situation for testing and can't get it figured out. I have an iOS app that just sends a request. And I've commented out everything on GAE except for the service. The service only logs a parameter and returns.
The iOS app I've tried using two different ways of sending the request. Neither works.
iOS Code:
/*
NSURL * url = [NSURL URLWithString:#"http://beermonster-gngrwzrd.appspot.com/TestParameter"];
ASIFormDataRequest * _fdrequest = [[ASIFormDataRequest alloc] initWithURL:url];
[_fdrequest setPostValue:#"hello" forKey:#"testkey"];
[_fdrequest startAsynchronous];
*/
NSURL * __url = [NSURL URLWithString:#"http://beermonster-gngrwzrd.appspot.com/TestParameter"];
NSMutableURLRequest * __request = [NSMutableURLRequest requestWithURL:__url];
[__request setHTTPMethod:#"POST"];
NSString * post = [NSString stringWithFormat:#"testkey=hello"];
[__request setHTTPBody:[post dataUsingEncoding:NSUTF8StringEncoding]];
[NSURLConnection sendSynchronousRequest:__request returningResponse:nil error:nil];
My App engine handler:
class TestParameter(webapp.RequestHandler):
def post(self):
logging.debug(self.request.get("testkey"))
self.response.out.write(self.request.get("testkey"))
print self.request.get("testkey")
def get(self):
logging.debug("get")
logging.debug(self.request.get("testkey"))
self.response.out.write(self.request.get("testkey"))
The output in the GAE logs shows the "get" code path which isn't correct.
Any ideas why POST requests would come into GAE as a GET? Is there some configuration in GAE that I missed?
Thanks!
Check the entry in app.yaml for the script that handles "/TestParameter". Does it specify "secure: always"? If it does and you make a non-secure connection you will get a 302 redirecting to the secure version.
To fix this either make your post over HTTPS or remove "secure: always" from the entry in app.yaml.
From what I can tell if you want to send POST requests to GAE. Make sure you do it on https. If you make the request on a non-https attempt, it sends back a 302 redirect to the https version of the request. But if whatever you're using to send the request doesn't correctly handle 302's it might resend the request incorrectly.

How to write data to the web server from iPhone application?

I am looking forward for posting some data and information on the web server through my iPhone application. I am not getting the way to post data to the web server from iPhone sdk.
It depends in what way you want to send data to the web server. If you want to just use the HTTP POST method, there are (at least) two options. You can use a synchronous or an asynchronous NSURLRequest. If you only want to post data and do not need to wait for a response from the server, I strongly recommend the asynchronous one, because it does not block the user interface. I.e. it runs "in the background" and the user can go on using (that is interacting with) your app. Asynchronous requests use delegation to tell the app that a request was sent, cancelled, completed, etc. You can also get the response via delegate methods if needed.
Here is an example for an asynchronous HTTP POST request:
// define your form fields here:
NSString *content = #"field1=42&field2=Hello";
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.example.com/form.php"]];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[content dataUsingEncoding:NSISOLatin1StringEncoding]];
// generates an autoreleased NSURLConnection
[NSURLConnection connectionWithRequest:request delegate:self];
Please refer to the NSURLConnection Class Reference for details on the delegate methods.
You can also send a synchronous request after generating the request:
[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
If you pass a NSURLResponse ** as returning response, you will find the server's response in the object that pointer points to. Keep in mind that the UI will block while the synchronous request is processed.

Resources