Search code examples
pythondjangoencodinggoogle-api-python-client

Getting UnicodeDecodeError when converting a InMemoryUploadedFile to Google MediaUpload


I am looking for your assistance with the following situation:

I am building a Django Application and I am orchestrating the instance on Google App Engine, Once your Google App Engine instance it's running it will enter into a "readonly" mode, and therefore Django can no longer write files into the "disk space"

With this mind, The Django application is receiving a 'File' submitted through a form, per Django documentation File Uploads are considered an UploadedFile Instance which is then becomes a subclass of InMemoryUploadedFile, If I attempt to pass this object to MediaUpload class I got the following message:

(<class 'TypeError'>, TypeError('expected str, bytes or os.PathLike object, not InMemoryUploadedFile'), <traceback object at 0x0000014D00669900>)

I need to convert this object to a bytes object as my end goal is to Upload this file into Google Drive using Google APIs

I tried to read the object (assuming the 'read' method will return the rawdata (bytes)) but I am getting a Decode error when I do that.

Uploading a File to Google Drive is described in their documentation but it seems the MediaFileUpload Class only accepts Strings/Paths unclear if accepts bytes. Looking at the error message I got "(<class 'UnicodeDecodeError'>, UnicodeDecodeError...."

Image of the error CMD errorcode.

def expupdate(request):
try:
    creds, _ = google.auth.default()
    service = build('drive', 'v3', credentials=creds)
    myfile = request.FILES['archivo']
    print(myfile.content_type)
    Mtype = myfile.content_type
    print(myfile.size)
    byte_object_after_read = myfile.read()
    media = MediaFileUpload(byte_object_after_read,mimetype=Mtype)
    file_metadata = {'name': 'test.jpeg'}
    file = service.files().create(body=file_metadata, media_body=media,
                                  fields='id').execute()
    fileid = file.get("id")
    print(fileid)

except:
    e = sys.exc_info()
    print('An error occurred:')
    print(e)

Solution

  • The solution was quite easy.

    It turns out Google offers MediaIoBaseUpload class which basically takes as an input a Bytes object and creates the necessary

    So the solution to collect a file from a FORM in django using appengine and then upload it to Google Drive without saving the file (manage in memory) is the following

    def expupdate(request):
        try:
            creds, _ = google.auth.default()
            service = build('drive', 'v3', credentials=creds)
            myfile = request.FILES['archivo']
            Mtype = myfile.content_type
            fh = myfile.open()
            media = MediaIoBaseUpload(fh,mimetype=Mtype)
            file_metadata = {'name': 'test.jpeg'}
            file = service.files().create(body=file_metadata, 
            media_body=media,fields='id').execute()                      
            fileid = file.get("id")
            print(fileid)
    
        except:
            e = sys.exc_info()
            print('An error occurred:')
            print(e)