I'm trying to upload a file to google drive from google app engine.
I have tried 2 different ways but I lose information in both.
The first one is the next one:
-The html form:
<html><body><form id='myForm' method='post' action='/guardar'
enctype='multipart/form-data' >
<input type="file" id="doc" name="doc" >
<input type="submit" value="Enviar"></form>
</body></html>
-The python code:
class guardar(webapp.RequestHandler):
#decorator.oauth_required
def post(self):
http = decorator.http()
service = build('drive', 'v2', http=http)
thefile = self.request.get('doc')
media_body = MediaInMemoryUpload(thefile, mimetype='text/plain', resumable=True)
response = service.files().insert(body={'title': 'prueba_si','mimeType': 'text/plain'},media_body=media_body).execute()
This way I lose the mimetype of the uploaded file and the title too; and I need both.
I have tried this other way but it always says that such file does not exist:
-The html file:
<html><body><form id='myForm' method='post' action='/guardar' >
<input type="file" id="doc" name="doc" >
<input type="submit" value="Enviar"></form>
</body></html>
-The python code:
class guardar(webapp.RequestHandler):
#decorator.oauth_required
def post(self):
http = decorator.http()
service = build('drive', 'v2', http=http)
thefile = self.request.get('doc')
mime_type=mimetypes.guess_type(thefile,strict=True)
media_body = MediaFileUpload(filename, mimetype=mime_type, resumable=True)
response = service.files().insert(body={'title': 'prueba_si','mimeType': mime_type},media_body=media_body).execute()
Thanks a lot for the help!
You don't need to pass the mime type in the media upload and also in the metadata. I would leave it just in the media upload.
You should not lose the title information, but I cannot reproduce your error.
Related
I'm trying to upload and image using Bootstrap-Vue Form File Input and send it to Flask Backend via POST using Axios library, then store in a folder.
My problem is that Flask can't find "file" in "request.files". Pretty sure I'm falling in a rookie mistake.
That's my code:
Frontend:
<template>
<div class="mx-5 container-fluid">
<div class="mx-5 row">
<div class="col-sm-10">
<b-form-file
type="file"
id="file"
v-model="file"
:state="Boolean(file)"
ref="file"
placeholder="Choose a file or drop it here..."
drop-placeholder="Drop file here..."
v-on:change="submitFile"
></b-form-file>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
file: null,
};
},
methods: {
submitFile() {
/* Initialize the form data */
const path = 'http://localhost:5000/single-file';
const formData = new FormData();
/* Add the form data we need to submit */
formData.append('file', this.file);
/* Make the request to the POST /single-file URL */
axios.post(path,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
}).then(() => {
// console.log('SUCCESS!!');
})
.catch(() => {
// console.log('FAILURE!!');
});
},
},
};
Backend:
from flask import Flask, jsonify, request, send_file, redirect, url_for
from werkzeug.utils import secure_filename
import os
# configuration
DEBUG = True
UPLOAD_FOLDER = '/images'
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
#app.route('/single-file', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
print('No file part')
return redirect(request.url)
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
print('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('download_file', name=filename))
return ''
if __name__ == '__main__':
app.run()
I get HTTP code 302 (redirect) and print in console 'No file part'.
Any help would be very apreciated.
I can't see an obvious mistake in your code, it seems that the request is correctly passed through from your frontend and backend.
What I would suggest is to use Postman to decouple your frontend and backend in this case. If you get a correct response when using Postman, you can narrow down that the error is in the frontend, the browser, or something about axios which is meddling with the request data.
Also, try to get an error message, or print why flask thinks "file" isnt in request.files, it should be there if everything works as intended
I followed the response for Get the data received in a Flask request to get to the flask documentation for the Request class: Each key in files is the name from the <input type="file" name="">, which means that most likely you have to change 'file' from file = request.files['file'] to point to the actual filename that was selected from the file selection menu.
html
<form #form enctype="multipart/form-data">
<input type="file" #upload name='uploadingFiles' (change)="uploadFiles(form)" multiple>
</form>
Angular
void uploadFiles(form) {
var formData = new FormData(form);
final request = new HttpRequest();
request.open('POST', 'http://localhost:8080/uploadMulti');
request.upload.onProgress.listen((ProgressEvent e) {
print('progress');
});
request.onLoad.listen((e) {
print('Uploaded');
});
request.send(formData);
}
How can I put image manipulation code here to reduce an image that is 4000X4000 to 600X600 and then replace it in the formData before sending ? Is it possible or is the formData just meta-data passed to the server and then server uses that to pull image bytes one file at a time ?
Angular has a good package to make a compression on the image before you upload it to your server.
you can use this https://www.npmjs.com/package/ngx-image-compress
and here is a good article if you have doubts about who you can do it.
https://medium.com/swlh/compress-image-and-send-it-to-an-api-in-angular-bc48e6ed3835
I'd like to know how could I make a report downloadable from my AngularJS Application?
The report is a .xlsx I can post the data, but the response is:
What I'd like is a downloadable file, or to open the .xlsx on Excel Online in other tab as in the preview.
How could I do that?
I usually recommend to create a hidden form and do plain http submit to jsreport /api/report. This is the most stable way and works across all browsers.
<form method='POST' target='_blank' action='/api/report' id='jsrForm'>
<input hidden='true' name='template[shortid]' value="41ucBgXKe"/>
<input hidden='true' name='data[foo]' value="Hello world"/>
<input hidden='true' name='options[Content-Disposition]' value="attachment; filename=myreport.pdf"/>
</form>
<script>
document.getElementById("jsrForm").submit();
</script>
Do you have control over the response? If so, add the content-disposition header and MediaType header to the response:
For System.Net.Http.HttpResponseMessage
var response = new HttpResponseMessage{Content = ...........}
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {
FileName = "mydoc.xlsx"
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
For System.Net.WebClient
var client = new WebClient();
client.Headers.Add("Content-disposition", "attachment");
client.Headers.Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
So far I used the usual method to post a form and redirect to the page I wanted to display like this :
The HTML part :
<form name="createArtistForm" method="post" action="/admin/createArtist">
Nom de l'artiste : <input type="text" name="artistName">
<input type="submit" value="Valider"/>
</form>
And the Scala part :
val artistBindingForm = Form(mapping(
"artistName" -> nonEmptyText(2)
)(Artist.formApply)(Artist.formUnapply)
)
def createArtist = Action { implicit request =>
artistBindingForm.bindFromRequest().fold(
formWithErrors => BadRequest(formWithErrors.errorsAsJson),
artist => {
artistId = Artist.saveArtist(artist)
Redirect(routes.ArtistController.artist(artistId))
}
)
}
And it worked fine, but now, the front end part of my app is managed by AngularJs so I submit the form with its http service like this :
$http.post('/admin/createArtist', {artistName : $scope.artiste.name})
The new artist is still well saved in my database, but the redirection has no effect.
What should I do in order to make the redirection work ? What am I missing ?
What I use to do in this cases is receive the result of the operation (error or success) and in case of success, redirect on the front end side with js (location = url).
I have this simple controller which uploads a file into the database. I have a working view which displays the form for uploading, but when I click on the upload button, I run into this error at the documentInstance.save() line: ArrayIndexOutOfBoundsException occurred when processing request:[POST]/myApp/documentFile/upload
class DocumentController {
def upload() {
def file = request.getFile('file')
if(file.empty) {
flash.message = "File cannot be empty"
} else {
def documentInstance = new Document()
documentInstance.filename = file.originalFilename
documentInstance.filedata = file.getBytes()
documentInstance.save()
}
redirect (action:'list')
}
}
Can anyone help me understand where the problem lies? Is the information I have given sufficient for answering this? If not please let me know.
UPDATE:
form element part of the gsp is as below.
<g:uploadForm action="upload">
<fieldset class="form">
<input type="file" name="file" />
</fieldset>
<fieldset class="buttons">
<g:submitButton name="upload" class="save" value="Upload" />
</fieldset>
</g:uploadForm>
Here is the Document domain class
class Document{
String filename
byte[] fileData
static constraints = {
filename(blank:false,nullable:false)
filedata(blank: true, nullable:true, maxSize:1073741824)
}
}
Try setting 'size' or 'maxSize' constraints on your domain objects 'filedata' field according to the size of the files you are uploading. Your database might be creating small columns that cannot hold the file size you are uploading. According to http://grails.org/doc/latest/guide/theWebLayer.html#uploadingFiles