Search code examples
pythonfine-uploader

Retrieving additional form fields from a fineuploader post


I'm replacing an existing file upload which uses html5 and jquery to pass an image as part of the request to a python method that strips the image and additional form fields out of the request before storing the image and writing a record to a database. I'm hoping to use the Fineuploader library and I have my html form successfully posting to my server using:

$(document).ready(function(){
$('#manual-fine-uploader').fineUploader({
   request: {
        endpoint: apiPrefix + '/box/' + $('#boxId').val() + '/upload' + apiSuffix,
        inputName: 'photo_file'

   },
   dataType: 'json',
   autoUpload: false
})
   .on('submit', function(event, id, name) {
      $(this).fineUploader('setParams', {
        title: $('#title').val(),
        date: $("#date").val(),
        is_with: $('#is_with').val(),
        latitude: "0.0",
        longitude: "0.0",
        location_desc: $('#location').val(),
        photo_caption: $('#photo_caption').val()}, id);
   });

$('#triggerUpload').click(function() {
   $('#manual-fine-uploader').fineUploader('uploadStoredFiles');
});
});

This adds the additional parameters to my request, and I can see in my Python Class that the request.FILES['photo_file'] has a value, but previously the additional form data was being captured by my python form as such:

class PhotoUploadAddForm(ModelForm):
class Meta:
    model = Entry
    exclude = ('type')

def __init__(self, *args, **kwargs):
    super(PhotoUploadAddForm, self).__init__(*args, **kwargs)

    self.fields['photo_caption'] = forms.CharField(required=False)
    self.fields['full_image_size'] = forms.IntegerField(required=False)
    self.fields['photo_file'] = forms.FileField(
        label='Select a file',
        help_text='max. 42 megabytes'
    )

However, sending the request via fineuploader I'm not getting and data into my model and therefore can't reference any of the request from my python class below:

class BoxPhotoUploadView(View):
"""
Adds new Photo to a box
"""
form = PhotoUploadAddForm 
print 'BoxPhotoUploadView'
permissions = (IsAuthenticated, )
def post(self, request, box_id, width = None, height = None):
    try:
        user = get_user_from_request(request)
        userProf = UserProfile.objects.get(user = user)   

        print 'Adding photo to boxid=' + box_id            
        print request.FILES['photo_file']._name  

        if userCanWriteToBox(request, box_id) is True:
              full_image = None

            if "full_image_size" in self.CONTENT and self.CONTENT["full_image_size"] is not None:
                full_image_size = self.CONTENT['full_image_size']
                retina_photo = self.CONTENT['photo_file']
            else:              
                full_image = self.CONTENT['photo_file']
                full_image_size = getSizeOfImageInKB(full_image)
                retina_photo = resize_photo_to_constrains(self.CONTENT['photo_file'], 640, 960)

            boxCreator = getBoxCreator(int(box_id))
             new_space_used = int(boxCreator.space_used) + full_image_size # get size of photo and increase used space

            if boxCreator.usage_plan != None and new_space_used < boxCreator.usage_plan.max_size:   
                photo = Photo(
                  type = 'PH',
                  title = self.CONTENT['title'],
                  date = self.CONTENT['date'],
                  is_with = self.CONTENT['is_with'],
                  latitude = self.CONTENT['latitude'],
                  longitude = self.CONTENT['longitude'],
                  location_desc = self.CONTENT['location_desc'],
                  photo_pic = '',
                  photo_caption = self.CONTENT['photo_caption'],
                  photo_file = retina_photo,
                  photo_full_size = full_image_size
                )
                print 'Photo Details from Post: ' + str(photo)           
                photo.save()
                photo.photo_pic = settings.SERVER_URL + 'api/photo/' + str(photo.id) + '/'
                photo.save()

                if full_image is not None:                      
                    write_file_to_folder(full_image, photo.title, settings.FULL_IMAGES_FOLDER)

                print 'start resize ' + str(datetime.now())
                resizeImage(photo.photo_file, 180, 200)
                resizeImage(photo.photo_file, 240, 140)
                resizeImage(photo.photo_file, 200, 110)
                print 'finish resize ' + str(datetime.now())


                boxCreator.space_used = new_space_used
                boxCreator.save()

                assocEntryToBox(request, photo.id, box_id)
                aprvd = requiredAprroval(userProf, box_id)

                if aprvd == True:
                    return {"message":'Photo waiting for approval.','photo_id':photo.id, 'user_id':userProf.id}

                return {"message":'Photo added successfully to box', 'photo_id':photo.id, 'user_id':userProf.id}
            else:
                if boxCreator == userProf:
                    error_message = {"error_message":"You ran out of space to upload content"}
                else:
                    error_message = {"error_message":boxCreator.user.first_name + " " + boxCreator.user.last_name + " ran out of space to upload content"}

                return Response(status.HTTP_404_NOT_FOUND, error_message)

        else:
            return Response(status.HTTP_404_NOT_FOUND, {"error_message": 'Error adding photo to box.'})
    except Exception, e:
        print e
        return Response(status.HTTP_404_NOT_FOUND, {"error_message": 'Error adding photo.'})

Just to add to this, the previous Jquery AJAX call that passed the file to my server was:

var data = new FormData();

data.append("date", $("#fdate").val() );
data.append("is_with", $('#is_with').val() );
data.append("latitude", "0.0" );
data.append("longitude", "0.0" );
data.append("location_desc", $('#location').val() );
data.append("photo_caption", $('#photo_caption').val() );
data.append("photo_file",       

document.getElementById("photo_loader").files[0] );

    $.ajax(apiPrefix + '/photo/box' + apiSuffix, {
        data: data,
        processData: false,  // tell jQuery not to process the data
        dataType: "json",
        cache: false,
        beforeSend: function ( xhr ) {xhr.overrideMimeType("multipart/form-data")},
        contentType: false,   // tell jQuery not to set contentTypedata: data3 
    },
    type: 'POST'
});

Solution

  • You are correctly sending the extra form data client-side, but I believe your server-side implementation is not correct. Django serializes incoming POST data into the request.POST QueryDict source and incoming multipart-encoded files into the request.FILES object. You should be able to access the incoming POST data much like any other Python dict:

    def post(self, request, box_id, width = None, height = None):
        # ...
        photo = Photo(
                  type = 'PH',
                  title = request.POST['title'],
                  date = request.POST['date'],
                  is_with = request.POST['is_with'],
                  latitude = request.POST['latitude'],
                  longitude = request.POST['longitude'],
                  location_desc = request.POST['location_desc'],
                  photo_pic = '',
                  photo_caption = request.POST['photo_caption'],
                  photo_file = retina_photo,
                  photo_full_size = full_image_size
                )
        # ...