Search code examples
javascriptpythonajaxgoogle-app-enginewebapp2

Upload Handler for File with Appended Information


I am creating a GAE app using WebApp2 that has a Data Object of Client. Each Client has a unique ID and I want to allow the user to upload one or many files associated with that particular Client object. I know that this is possible using blobstore, GCS, but am experimenting with Titan Files, which has the ability to use the blobstore backend while allowing me to create a quasi-file directory system for my users. I am fairly new to GAE programming, so any help would be greatly appreciated!

I am using the FormData object in order to append other useful information to my file (filename, and the directory path with a "folder" and a "sub-folder" that I want to write the file to). From the firebug console, my post appears to be firing correctly as I am seeing the post with lots of strange characters (the file) and other data I am appending to the file (the filename and path I want it written to as described above). That said, I am getting the following error:

Traceback (most recent call last):
File "C:\lib\webapp2-2.5.2\webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "C:\lib\webapp2-2.5.2\webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "C:\lib\webapp2-2.5.2\webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "C:\lib\webapp2-2.5.2\webapp2.py", line 1102, in __call__
return handler.dispatch()
File "C:\lib\webapp2-2.5.2\webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "C:\lib\webapp2-2.5.2\webapp2.py", line 570, in dispatch
return method(*args, **kwargs)

File "C:\Users\Owner\Documents\vein\vann-vein\main.py", line 121, in post
myfile = self.request.post(self)
File "C:\lib\webob-1.1.1\webob\request.py", line 1238, in __getattr__
raise AttributeError(attr)
AttributeError: post
INFO     2015-03-21 13:55:19,667 module.py:666] default: "POST /uploadfile     HTTP/1.1" 500 1469

I am fairly certain the issue is in my UploadHandler, but will provide other MVC elements for full context... I'm not clear on whether I am using the GET/POST correctly.

My HTML Form:

    <div class="form-group">
        <label class="control-label col-sm-4" for="clientNumber">Client Number*:</label>
            <div class="col-sm-8">
                <input type="text" class="form-control" id="clientNumber" placeholder="Client 1111111" disabled>
            </div>
    </div>

    <div class="form-group">   
        <label class="control-label col-sm-4" for="clientDocs">Client Docs:</label>                     
            <div class="col-sm-8">
                <input type="file" type="file" name="file" id="file"><br>
                <button type="button" class="btn btn-info" id="clientDocsButton" onclick="addFile()" disabled>Add File</button><br>
            </div>
    </div>

My Javascript being called:

function addFile()
{
console.log("Pre-Instantiation.");
var filepath = window.location.pathname;
var subfolder = document.getElementById("clientNumber").value
var myfile = document.getElementById("file");
var filename = document.getElementById("file").value;

console.log("Post-Instantiation.");
var formData = new FormData();
formData.append('thefile', myfile.files[0]);
formData.append('filepath', filepath);
formData.append('subfolder', subfolder);
formData.append('filename', filename);
console.log("Pre-AJAX.");
console.log(typeof formData['thefile']);

$.ajax({
    url: '/uploadfile',  //Server script to process data
    type: 'POST',
    xhr: function() {  // Custom XMLHttpRequest
        var myXhr = $.ajaxSettings.xhr();
        if(myXhr.upload){ // Check if upload property exists
            myXhr.upload.addEventListener('progress',progressHandlingFunction, false); // For handling the progress of the upload
        }
        return myXhr;
    },
    //Ajax events
    success: function(response) {
        bootbox.alert(response);
    },
    error : function(xhr,errmsg,err) {
        bootbox.alert(xhr.status);
    },
    data: formData,
    //Options to tell jQuery not to process data or worry about content-type.
    cache: false,
    contentType: false,
    processData: false
})};

My Main - UploadHandler:

class UploadHandler(webapp2.RequestHandler):
def post(self):
    myfile = self.request.post(self)
    myfile = formData['thefile']
    filepath = myfile['filepath']
    subfolder = myfile['subfolder']
    filename = myfile['filename']

    files.File('/' + filepath + '/' + subfolder + '/' + filename).write(myfile)
    self.response.write("Save successful")

Note: The files.File().write() method above is part of the Titan Files library which is being imported into my Main.py


Solution

  • You can get all the submitted data from the request object, via the get method, no need to create any other objects:

    class UploadHandler(webapp2.RequestHandler):
        def post(self):
            myfile = self.request.get('thefile')
            filepath = self.request.get('filepath')
            subfolder = self.request.get('subfolder')
            filename = self.request.get('filename')
    
            files.File('/' + filepath + '/' + subfolder + '/' + filename).write(myfile)
            self.response.write("Save successful")