views:

314

answers:

3

My basic question is this: Is there an equivalent of

form = MyForm(request.POST, request.FILES)

when handling file uploads using the webapp framework on Google App Engine?

I know that I can pull out specific uploaded file data using self.request.get('field_name') or a FieldStorage object using self.request.params['field_name'], but in my case I do not know the field names in advance. I would like to let the form object take care of pulling the data it needs out of the request (especially since the forms, and thus the incoming field names, have prefixes).

I'm porting a sort of generic CMS system from Django (already running on App Engine) to Google's webapp framework, and this is the last major stumbling block. When a new item is created, I'd like to be able to just pass the POSTed parameters and files straight to the Django form object for that item, so that I don't have to know ahead of time what fields are in the form and which of those fields are file uploads. This was possible using Django, but I can't see any easy way to do it in the webapp framework.

A: 

Have a look at app-engine-patch. request.FILES is supposed to work if you use it.

There is also a little snippet here, but I have not tested it:

if request.method == 'POST':
    form = MyImageUploadForm( request.POST, request.FILES)
    if form.is_valid():
        themodel = MyImageModel()
        themodel.data = form.cleaned_data['file'].read()
        themodel.content_type = form.cleaned_data['file'].content_type
        themodel.put()
    else:
        form = MyImageUploadForm()
jbochi
Unfortunately, I am moving *away* from Django *to* the built-in webapp framework.
Will McCutchen
+1  A: 

Here's the solution I came up with. I added the following method to my custom webapp.RequestHandler subclass:

# Required imports
import cgi
from django.core.files.uploadedfile import SimpleUploadedFile

def get_uploaded_files(self):
    """Gets a dictionary mapping field names to SimpleUploadedFile objects
    for each uploaded file in the given params.  Suitable for passing to a
    Django form as the `files` argument."""
    return dict((k, SimpleUploadedFile(v.filename, v.file.read()))
                for k, v in self.request.params.items()
                if isinstance(v, cgi.FieldStorage) and v.file)

Now, when handling uploaded files, I can do something like the following:

form = MyForm(self.request.params, self.get_uploaded_files())

This works well for me so far.

(I don't know if it's bad form to answer my own question. I'm sorry if it is.)

Will McCutchen
Check out the bottom of the first entry in the FAQ: "It's also perfectly fine to ask and answer your own question,..."
Colonel Sponsz
A: 

self.request.arguments() contains all the elements that you could retrieve separately using self.request.get('field_name') if you knew 'field_name'.

Since you don't know the name of your fields in advance, you might want to loop on all of it's elements. This would work just fine if the names of your fields have a fixed prepend, such as photo_cat and photo_dog.

Emilien
If you look at the solution I posted above, this is exactly what I'm doing. Except that I'm looping through `self.request.params.items()` instead. It's working for me.
Will McCutchen