Sending a word document without saving it on the flask server - python

Good day. Today I'm trying to send a document generated on the server to the user on the click of a button using Flask.
My task is this:
Create a document (without saving it on the server). And send it to the user.
However, using a java script, I track the button click on the form and use fetch to make a request to the server. The server retrieves the necessary data and creates a Word document based on it. How can I form a response to a request so that the file starts downloading?
Code since the creation of the document. (The text of the Word document has been replaced)
python Falsk:
document = Document()
document.add_heading("Some head-title")
document.add_paragraph('Some text')
f = BytesIO()
document.save(f)
f.seek(0)
return send_file(f, as_attachment=True, download_name='some.docx')
However, the file does not start downloading.
How can I send a file from the server to the user?
Edits
This is my js request.
fetch('/getData', {
method : 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
someData: someData,
})
})
.then(response =>
response.text()
)
.then(response =>{
console.log(response);
});
This is my html
<form action="" name="getData" method="post" enctype="multipart/form-data">
<button type = "submit" name = "Download">Download</button>
</form>

You need to specify the mimetype, It tries to detect the mimetype from the filename but since we are not saving it we need to specify the mimetype.
return send_file(f, mimetype='application/msword', as_attachment=True, download_name='output.doc')

Related

Why is my request body not being populated correctly

I am trying to test a very simple Express App. I have my Express set up in a typescript file as follows to respond with the body of the request that it receives:
app.listen(3000, () => console.log('Server running on port 3000'))
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(bodyParser.json())
app.get('/test', (req, res) => {
res.send(req.body)
});
I am trying to call this endpoint in a python file as follows
testUrl = 'http://localhost:3000'
path = '/test'
header = {
'Content-Type': 'application/json',
}
body = {
'artistName': 'test',
}
response = requests.request(
method="GET",
url = testUrl + path,
params=header,
data=body,
)
print(response._content)
When I run the python file, all it prints out is a set of empty brackets, telling me that the body of the request it is receiving is empty. Why is the body empty if I am setting the data parameter to a populated json object? Am I using the wrong parameters? Thanks for the help!
I don't know what you mean to do with res.send(req.body) in your Express code, but req.body is not used for a GET request in Express. That's used for a POST or PUT.
Parameters for a GET request are put in the URL as part of the queryString and will appear in the req.query object in Express.
I think your mistake is in the request,
Because you are sending your header as params

Unable to parse json data from ajax in flask

I am trying to pass data from ajax to routes.py in flask through json. I have sometimes made it pop up a dialog box with the actual data, but I am unable to parse the data or have it appear on a webpage itself..(I eventually need to have this data manipulate sql db but for now I am just trying to be able to manipulate the data).
routes.py
#app.route("/post", methods=['GET', 'POST'])
def post():
data = request.get_json()
jsonify(data=data)
x = request.json['index']
return render_template('post.html', x=x)
request.json['index'] does not work and throws TypeError: 'NoneType'
if I return jsonify(data=data) instead of have it before the return, I can see the data in a dialog window when I go to localhost:5000/post
index.html
<script>
$(function() {
$( "#sortable" ).sortable({
update: function(event, ui) {
var postData = $(this).sortable('serialize');
}
});
});
function postSave() {$( "li" ).each(function( index ) {
console.log( index + ": " + $( this ).attr('id') );
$.ajax({
url: '/post',
data: JSON.stringify({ "index" : index, "id" : $( this ).attr('id') } ),
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
alert(JSON.stringify(data));
}
});
var url = "/post";
$(location).attr('href',url);
});
}
</script>
post.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- simply be able to parse through the data and print it here for testing purposes -->
</body>
</html>
all help is greatly appreciated, I am pulling my hair out as we speak :)
Your post route has been configured to handle both GET and POST requests, but you don't distinguish between GET and POST requests. Since there is no distinction between the two type of requests if your browser sent off a GET request to your post route on your flask server there will be no JSON data in your request. A simple conditional like the following: if flask.request.method == 'POST': can be used to distinguish between the two types of requests. With that being said, maybe you could try out something like the following:
#app.route('/post', methods=['GET', 'POST'])
def post():
if request.method == "POST":
req_data = request.get_json()
x = req_data['index']
return render_template('post.html', x=x)
else: # GET request
# handle as you see fit probably want to render a page
# with inputs for a user to fill out
return render_template(<page_you_wish_to_render>)
If this doesn't work could you please print out req_data? So we can see what the request looks like as it might be invalid JSON.
Also, your ajax call looks a little off, maybe you could edit just the Ajax part to something like the following:
$.ajax({
type : 'POST',
url : "{{url_for('post')}}",
contentType: 'application/json;charset=UTF-8',
data : {'index':index}
});
Lastly, I would put a debugger statement right before you send off your ajax request to make sure the request is correct.
Hopefully that helps!

Populating backend script for Django form

I'm trying to create a web front end to do various management tasks with Django. I've never needed a front end but now they want different BU's to be able to utilize them and they need something pretty to press a button on. So what I want to do is:
User inputs form data and submits it
Site access's external script using the post data as args
User is redirected to confirmation page
Right now I can post data and I can run the script with args, I just don't know how to combine the two. Any help or hints on what I should look into would be greatly appreciated. I didn't post snippets because I'd have to sterilize them but upon request I can if it's needed in order to help.
The easiest way to interact directly is to leverage Ajax, whereby you use Ajax Post to send JSON to Django and then handle the arguments as a dict(). Here is an example:
In browser (JQuery/JavaScript):
function newModule() {
var my_data = $("#my_element").val(); // Whatever value you want to be sent.
$.ajax({
url: "{% url 'modules' %}", // Handler as defined in Django URLs.
type: "POST", // Method.
dataType: "json", // Format as JSON (Default).
data: {
path: my_data, // Dictionary key (JSON).
csrfmiddlewaretoken:
'{{ csrf_token }}' // Unique key.
},
success: function (json) {
// On success do this.
},
error: function (xhr, errmsg, err) {
// On failure do this.
}
});
In server engine (Python):
def handle(request):
# Post request containing the key.
if request.method == 'POST' and 'my_data' in request.POST.keys():
# Retrieving the value.
my_data = request.POST['my_data']
# ...
Now all you need to do is to direct your HTML form to call the JavaScript function and communicate the data to the engine.
To redirect the user to another page upon success, you can use this in your success function:
window.location.href = "http://www.example.com";
Which simulates a reaction similar to that of clicking on an anchor tag (link).
Hope this helps.

Passing data between client and Flask

I have a Flask application where I have a form that collects some user input. That input is then passed as JSON data via an AJAX call to a function in my Python script.
This function calls an API, gets some new data and then returns a redirect URL to the AJAX call. On success, AJAX then redirects to this new template with window.location.href.
I tried 'passing' the first view function, the_search, over to the second view function to then render the appropriate template but this didn't do the trick unfortunately. I've also tried setting the data as a session variable and then accessing it in the template but this doesn't seem to work either.
My issue
How can I access the variable 'response' within the redirected template, results.html?
AJAX script
...
$.ajax({
type: 'POST',
url: '/the_search',
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
success: function(data, status) {
window.location.href = data['website'];
},
error: function() {
console.log('there was an error');
}
})
...
Python script
#app.route('/the_search', methods=("POST", 'GET'))
def the_search():
data = json.loads(request.data)
lat = data['latitude']
longitude = data['longitude']
response = unirest.get("https://zilyo.p.mashape.com/search?latitude={}&longitude={}".format(lat, longitude),
headers={
"X-Mashape-Key": "k6HBYxvy88mshQ6Yg1xPVuv7Vg9Np1GZj7IjsnPxploykdpaHA",
"Accept": "application/json"})
session['search_results'] = response.body
return jsonify({'website': '/results'}), 200
#app.route('/results', methods=('POST', 'GET'))
def results():
#How can I pass the_search view function to here while still having access to the response data
print session['search_results']
return render_template('results.html')

How to parse Cordova/Phonegap file upload in flask app

I've been working on a Cordova app, using the Ionic framework. I'm trying to do a "File Transfer" to a my Python-Flask back-end, but I keep getting "400 Bad Request". I'm quite sure that the error is caused by the request parsing method in flask (I'm currently using "request.file[]").
But I can't seem to figure out how to parse the POST request properly.
The POST is send in chunkedMode, with the mime type "image/jpeg", not sure if this could have any impact (My Nginx proxy is set up to properly receive POSTs in chunked mode).
My client code:
$scope.getPhoto = function() {
$scope.modal.show();
navigator.camera.getPicture(
// Succes
function(imageURI){
// Upload image
var options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType = "image/jpeg";
options.trustAllHosts = true;
options.chunkedMode = true;
var ft = new FileTransfer();
// Initiate upload
ft.upload(imageURI, encodeURI("http://192.168.1.53/"),
// Succes
function(succes){
alert(succes.response);
console.log(succes.response);
},
function(error){
alert(error.target);
console.log(error);
},
options
);
},
// Error
function(message) {
console.log('get picture failed');
},
// Options
{
quality: 100,
encodingType: Camera.EncodingType.JPEG,
allowEdit : false,
correctOrientation: true,
destinationType: navigator.camera.DestinationType.FILE_URI,
sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY
}
);
I got this working in PHP, witht the following code:
if(isset($_FILES["somefile"]))
{
//Filter the file types.
if ($_FILES["somefile"]["error"] > 0)
{
echo "error:" + $_FILES["somefile"]["error"];
}
else
{
callSomeFunction();
}
} // End of function
My current flask app looks something like this:
#app.route("/", methods=["GET", "POST"])
def upload_file():
if request.method == "POST":
file = request.files["file"]
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config["UPLOAD_FOLDER"], filename))
#fileStream = file.stream
#print(opencvDataFromStream(fileStream))
#processImage(filename)
return processImage(filename)
return """
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
"""
As you can see it returns a form, and when the POST is send through the form, the request is treated as expected.
But when the POST request is send through the cross side Cordova client, I get the bad request error.
Would any one happen to know how to fix this?
Sincerely a flask n00b.
So I screwed up...
The error was simply caused, due to the fact, that the fileKey ("imageToScan") parameter in the client wasn't the same fileKey as my Flask back-end was expecting ("file").

Categories