I am making a rest API for multipart request API code is working fine but I am unable to get URL of multiple files any body know how to get this done code I done so far:
#app.route('/multiple-files-upload', methods=['POST'])
def upload_file():
randNum = random.randint(10, 900)
appendRand = "SWM-"+str(randNum)
date = str(datetime.date(datetime.now()))
# subject = request.form['subject']
# details = request.form['details']
# province = request.form['province']
# district = request.form['district']
# tehsil = request.form['tehsil']
# lat = request.form['lat']
# lon = request.form['lon']
# username = request.form['username']
# status = request.form['status']
files = request.files.getlist('files')
errors = {}
data = {}
success = False
for file in files:
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
appendDate = str(appendRand)+"-"+date+"-"+filename
file.save(os.path.join(app.config['UPLOAD_FOLDER'],appendDate))
success = True
else:
errors[file.filename] = 'File type is not allowed'
# if success and errors:
# errors['message'] = 'File(s) successfully uploaded'
# resp = jsonify(errors)
# resp.status_code = 500
# return resp
if success:
filename = secure_filename(file.filename)
url = appendPath +'/'+appendDate
data = {"URL":url}
resp = jsonify({"Error":"flase","Code":"00",'Message': 'Files successfully uploaded',"Data":data})
resp.status_code = 200
return resp
else:
resp = jsonify(errors)
resp.status_code = 500
return resp
Response I get:
{
"Error": "flase",
"Code": "00",
"Message": "Files successfully uploaded",
"Data": {
"URL": "/uploads/SWM-882-2022-02-17-API.PNG"
}
}
Desired response:
{
"Error": "flase",
"Code": "00",
"Message": "Files successfully uploaded",
"Data": {
"URL": "/uploads/SWM-882-2022-02-17-API.PNG"
"URL": "/uploads/SWM-882-2022-02-17-API.PNG"
"URL": "/uploads/SWM-882-2022-02-17-API.PNG"
"URL": "/uploads/SWM-882-2022-02-17-API.PNG"
}
}
E.g. when I upload multiple files I get multiple URLs now only get 1 URL
The example below follows your code and shows how to upload multiple files to the server using AJAX. As I am assuming you are trying.
Depending on whether an error occurs or not, a different response from the server is returned.
This contains a message and possible error messages, each of which is assigned to a file name. Furthermore, the resulting urls of the successfully uploaded files are listed.
Flask (app.py)
import os
from flask import Flask
from flask import (
jsonify,
render_template,
request,
url_for
)
from datetime import date
from random import randint
from werkzeug.utils import secure_filename
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = app.static_folder
#app.route('/')
def index():
return render_template('index.html')
def allowed_file(filename):
# Your validation code here!
return True
#app.route('/upload', methods=['POST'])
def upload():
errors = {}
data = []
prefix = f'SWM-{randint(10,900)}-{date.today()}'
files = request.files.getlist('files')
for file in files:
if file.filename != '' and allowed_file(file.filename):
filename = secure_filename(file.filename)
filename = f'{prefix}-{filename}'
file.save(os.path.join(
app.config['UPLOAD_FOLDER'],
filename
))
data.append({ 'url': filename })
else:
errors[file.filename] = 'File type is not allowed'
return jsonify({
'message': 'An error has occurred.' if errors else 'Files successfully uploaded',
'errors': errors,
'data': data
}), 400 if errors else 200
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Index</title>
</head>
<body>
<form name="my-form" method="post">
<input type="file" name="files" multiple />
<input type="submit" />
</form>
<script type="text/javascript">
((uri) => {
const formElem = document.querySelector('form[name="my-form"]');
formElem.addEventListener('submit', evt => {
evt.preventDefault();
fetch(uri, {
method: 'post',
body: new FormData(evt.target)
}).then(resp => resp.json())
.then(data => {
console.log(data);
});
evt.target.reset(),
});
})({{ url_for('upload') | tojson }});
</script>
</body>
</html>
Related
This is my Kotlin code
imageButton.setOnClickListener {
val gallery = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI)
startActivityForResult(gallery, pickImage)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == pickImage) {
imageUri = data?.data
imageView.setImageURI(imageUri)
//get email from preferences
val prefs = getSharedPreferences("db", Context.MODE_PRIVATE)
val email = prefs.getString("email", "")
val client = AsyncHttpClient(true, 80, 443)
val data = JSONObject()
data.put("files", imageUri.toString())
data.put("email", email.toString())
val condata = StringEntity(data.toString())
//post it to api
client.post(this, "https://jereson.pythonanywhere.com/editdp",
condata, "multipart/form-data; boundary=eBayClAsSiFiEdSpOsTiMaGe",
object: JsonHttpResponseHandler() {
override fun onSuccess(
statusCode: Int,
headers: Array<out Header>?,
response: JSONObject?
) {
Toast.makeText(applicationContext, "image updated successfully", Toast.LENGTH_LONG).show()
}
override fun onFailure(
statusCode: Int,
headers: Array<out Header>?,
responseString: String?,
throwable: Throwable?
) {
Toast.makeText(applicationContext, "Something went wrong "+statusCode, Toast.LENGTH_LONG).show()
}
})//ends the client.post
}//ends resultcode if
This is my python code
#app.route('/editdp', methods = ['POST', 'GET'])
def editdp():
connection = pymysql.connect(host ='jereson.mysql.pythonanywhere-services.com', user
='jereson', password ='jemuki.compassword#4321', database ='jereson$jemuki_com254_254')
cursor = connection.cursor()
from flask import request
json = request.json
email = json['email']
files = json['files']
files = request.files.getlist('files')
#print(files)
for file in files:
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
cursor.execute('UPDATE signup SET dp=%s WHERE email=%s ',[filename, email])
connection.commit()
print(file)
cursor.close()
response = jsonify({"message":"updated successfully"})
return response
When i post an image the code Toasts image updated successfully but whenever i check mysql the filename is not uploaded and also in the folder the image is not uploaded.The email from preferences is just to enable me update the image to the correct rowAny help would be highly appreciated.
I am new in Flask. My goal is to generate dynamic div containers every time I upload a dxf file and next submit happens. For example: one file uploaded- one div shown; two files uploaded- two divs shown and so on.
I can convert uploaded dxf files to .png images and I would like to show these images in div elements displayed after every upload.
I use input tag to upload files (type='file') and Java Script to generate dynamic elements (divs and their child tags).
The problem is that every time I upload file, the template is loading again and no new content is shown except the image of the last uploaded dxf. Please, give me a piece of advice to solve it.
HTML
...
<form enctype="multipart/form-data" id="uploadForm" action="/upload_files" name="uploadForm" method="post">
DXF file: <input type="file" id="dxfUpload" onchange="form.submit(); createConfigure();" name="dxfUpload" />
<div id="calcHolder" name="calcHolder">
<script type="text/javascript">
function createConfigure() {
var div = document.createElement("div");
div.id = "dxf-"+Math.random() * 100000000000000000 + "-"
+ window.performance.now() * 100000000000000000;
id_div=div.id;
div.className = 'border pad';
div.style.width = "640px";
div.style.height = "200px";
document.getElementById("calcHolder").appendChild(div);
var img = document.createElement("img");
img.setAttribute("src", "{{url_for('static', filename=dxfName+'.png')}}");
img.setAttribute("alt", "no image");
img.setAttribute("height", "120px");
img.setAttribute("width", "120px");
document.getElementById(id_div).appendChild(img);
var array = ["Carbon Steel","Stainless Steel","Aluminium"];
var selectMaterial = document.createElement("select");
document.getElementById(id_div).appendChild(selectMaterial);
for (var i = 0; i < array.length; i++) {
var option = document.createElement("option");
option.value = array[i];
option.text = array[i];
selectMaterial.appendChild(option);
}
var selectThickness = document.createElement("select");
document.getElementById(id_div).appendChild(selectThickness);
for (i = 1; i <= 16; i++) {
var opt = document.createElement('option');
//opt.value = i;
opt.innerHTML = i + ' mm';
selectThickness.appendChild(opt);
}
var quantity = document.createElement("input")
quantity.type="number";
quantity.value="1";
quantity.name="quantity";
quantity.min="1";
quantity.max="50";
quantity.onkeyup= function maxReach(){if(quantity.value > 50) quantity.value=50;};
document.getElementById(id_div).appendChild(quantity);
var btn = document.createElement("button");
btn.innerHTML = "Delete";
btn.type = "button";
document.getElementById(id_div).appendChild(btn);
btn.onclick = function() {div.remove();};
}
</script>
{{ html | safe }}
</div>
</form>
...
Python
#app.route('/upload_files', methods=['POST'])
def upload_files():
try:
if request.method == 'POST':
dxf_file = request.files['dxfUpload']
full_filename = os.path.join(app.config['UPLOAD_FOLDER'],dxf_file.filename)
dxf_file.save(full_filename)
first = DXF2IMG()
first.convert_dxf2img([full_filename],img_format='.png')
html="<img src="+url_for('static', filename=dxf_file.filename+'.png' )+" width='120' height='120' />"
return render_template('upload_files.html',dxfName=dxf_file.filename, html=html)
except:
...
#something happens
The result now
Desired result
Once the form.submit() function is executed, the form will be sent as a regular post request. For this reason, the following function is no longer executed and the entire page is reloaded.
In order to submit the form and change the content of the existing page, it is necessary to use AJAX.
This example shows you how to submit the form to the server and receive a JSON response containing the URLs of the received file and the generated image.
As soon as the submit button is pressed, the form data is packed into a FormData object and sent via AJAX using the fetch function. The browser's default behavior for a submit event is suppressed and the form is reset. The received file is processed by the server and the associated URLs are sent back to the client in JSON format. Now the document can be changed with the received data.
Remember this is just a minimal example to help you achieve your goals and implement your concept.
Flask (app.py)
import os
import ezdxf
from ezdxf.addons.drawing import matplotlib
from flask import Flask
from flask import (
jsonify,
make_response,
render_template,
url_for
)
from werkzeug.utils import secure_filename
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
def dxf2png(source, target):
doc = ezdxf.readfile(source)
msp = doc.modelspace()
auditor = doc.audit()
if auditor.has_errors:
raise Exception('Conversion failed.')
matplotlib.qsave(doc.modelspace(), target)
#app.route('/upload', methods=['POST'])
def upload():
if 'dxf-file' in request.files:
file = request.files['dxf-file']
if file.filename != '':
filename = secure_filename(file.filename)
filepath = os.path.join(app.static_folder, filename)
destname, _ = os.path.splitext(filename)
destname = f'{destname}.png'
destpath = os.path.join(app.static_folder, destname)
file.save(filepath)
try:
dxf2png(filepath, destpath)
except:
os.remove(filepath)
return make_response('', 400)
return make_response(
jsonify(
target=url_for('static', filename=filename),
preview=url_for('static', filename=destname)
),
200
)
return make_response('', 400)
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Index</title>
<style media="screen">
.preview {
width: 120px;
height: auto;
}
</style>
</head>
<body>
<form name="dxf-upload" method="post" enctype="multipart/form-data">
<input type="file" name="dxf-file" />
<input type="submit" />
</form>
<div id="dxf-files"></div>
<script type="text/javascript">
((uri) => {
function createPreview(target, preview) {
const divElem = document.createElement('div');
divElem.innerHTML = `<img src="${preview}" class="preview" />`;
const outElem = document.getElementById('dxf-files');
outElem.append(divElem);
}
const form = document.querySelector('form[name="dxf-upload"]');
form.addEventListener('submit', evt => {
evt.preventDefault();
const formData = new FormData(evt.target);
fetch(uri, {
method: 'POST',
body: formData
}).then(resp => resp.json())
.then(data => {
const { target, preview } = data;
createPreview(target, preview);
});
evt.target.reset();
});
})({{ url_for('.upload') | tojson }});
</script>
</body>
</html>
I have processed the data retrieved from some API in a flask route, extracted the json needed and then stored it in a dictionary. Now, how do I make the processed data appear in a new HTML? Is it a good way to preprocess the data in a flask function, what if the preprocess takes a lot of steps?
Flask python code x.py:
#app.route('/test', methods = ['GET'])
def get_from_api():
url = "https://xxxx"
API_KEY = "xxxx"
params = {
'token' : API_KEY
}
response = requests.get(url, params).json()
city = response['city']
state = response['region']
postal = response['postal']
conutry = response['country']
location = response['loc']
data = {
"city" : city,
"state" : state,
"postal" : postal,
"country" : conutry,
"location" : location
}
Next is the x.html for displaying the data
<div class = "element_val">
<li><div id = "city">null</div></li>
<li><div id = "state">null</div></li>
...
<li><div id = "location">null</div></li>
</div>
How to retrieve the data in flask and put the data in html, and make the html be rendered in '/test'?
#app.route('/test')
def test_route():
user_details = {
'name': 'John',
'email': 'john#doe.com'
}
return render_template('test.html', user=user_details)
<!DOCTYPE html>
<html>
<head>
<title>test</title>
</head>
<body>
<!-- use {{}} to access the render_template vars-->
<p>{{user.name}}</p>
<p>{{user.email}}</p>
</body>
</html>
I tried using
GET https://graph.microsoft.com/v1.0/me/photo/$value to get the user's image/photo but it only returns an HTTP 200 status code. How can I get the binary data?
I've also tried using the content.property as suggested in a similar post but get a .format is not an attribute of the dict.
#app.route("/photo")
def get_photo():
token = _get_token_from_cache(app_config.SCOPE)
if not token:
return redirect(url_for("login"))
photo = requests.get(app_config.PHOTO_ENDPOINT,
headers={'Authorization': 'Bearer ' + token['access_token']})
print(photo.status_code)
return photo
Gets a profile photo, and optionally saves a local copy. Returns a tuple of the raw photo data, HTTP status code, content type, and saved filename. Refer to this sample.
def profile_photo(session, *, user_id='me', save_as=None):
"""Get profile photo, and optionally save a local copy.
session = requests.Session() instance with Graph access token
user_id = Graph id value for the user, or 'me' (default) for current user
save_as = optional filename to save the photo locally. Should not include an
extension - the extension is determined by photo's content type.
Returns a tuple of the photo (raw data), HTTP status code, content type, saved filename.
"""
endpoint = 'me/photo/$value' if user_id == 'me' else f'users/{user_id}/$value'
photo_response = session.get(api_endpoint(endpoint),
stream=True)
photo_status_code = photo_response.status_code
if photo_response.ok:
photo = photo_response.raw.read()
# note we remove /$value from endpoint to get metadata endpoint
metadata_response = session.get(api_endpoint(endpoint[:-7]))
content_type = metadata_response.json().get('#odata.mediaContentType', '')
else:
photo = ''
content_type = ''
if photo and save_as:
extension = content_type.split('/')[1]
filename = save_as + '.' + extension
with open(filename, 'wb') as fhandle:
fhandle.write(photo)
else:
filename = ''
return (photo, photo_status_code, content_type, filename)
Alternate approach, based on the original question's code, if you want to display the resulting image on a web page.
from base64 import b64encode
#app.route("/photo")
def get_photo():
token = _get_token_from_cache(app_config.SCOPE)
if not token:
return redirect(url_for("login"))
response = requests.get(
app_config.PHOTO_ENDPOINT,
headers={'Authorization': 'Bearer ' + token['access_token']}
)
content_type = response.raw.getheader('Content-Type')
return render_template('index.html',
photo_data=b64encode(response.content),
photo_content_type=content_type)
Then in the index.html template you can display the photo like so:
<html>
<body>
<img src="data:{{ photo_content_type }};base64,{{ photo_data }}" />
</body>
</html>
Call Api: -
Axios.get('https://graph.microsoft.com/v1.0/me/photo/$value', {
headers: { 'Authorization': 'Bearer '+AccessToken },
responseType: 'blob'
}).then(o => {
const url = window.URL || window.webkitURL;
const blobUrl = url.createObjectURL(o.data);
self.setState({ imageUrl: blobUrl });
})
JSX: -
<img alt="image" src={this.state.imageUrl} />
Here is what worked for me:
from base64 import b64encode
token = _get_token_from_cache(app_config.graphSCOPE)
aadPhotoURI = "https://graph.microsoft.com/v1.0/me/photo/$value"
response = requests.get(aadPhotoURI, headers={'Authorization': 'Bearer ' +
token['access_token']},)
content_type = response.raw.getheader('Content-Type')
return render_template(
'usersettings.html',
photo_data = b64encode(response.content).decode(),
photo_content_type = content_type)
then in the .html page added:
<img class="account-img" alt="" src="data:{{ photo_content_type }};base64,{{ photo_data }}"/>
CSS for account-img:
.account-img {
width: 40px;
float: right;
border-radius: 50%;
}
I need to let the Django auto download the generated file.
Tried all different solutions online, none of them works.
Views.py
def validate(request):
if request.method == 'POST':
filename = request.POST.get('source_file')
file_path = os.path.join(settings.MEDIA_ROOT, 'SourceFiles', filename)
region = request.POST.get('region')
product_type = request.POST.get('product_type')
result = validateSource.delay(file_path, region, product_type)
output_filepath, log_filepath = result.get()
if os.path.exists(output_filepath) and os.path.exists(log_filepath):
zip_filename = zipFiles([output_filepath, log_filepath], filename)
zip_filepath = os.path.join(settings.MEDIA_ROOT, zip_filename)
response = FileResponse(open(zip_filepath, 'rb'), as_attachment=True)
return response
raise Http404
Template: code for the form POST.
$(document).on('submit', '#productForm', function(e){
e.preventDefault();
var inputFilePath = document.getElementById('sourceFileInput').files.item(0).name;
$.ajax({
method: 'POST',
url: 'validate/',
data: {
source_file: inputFilePath,
region: $("#Region-choice").val(),
product_type: $("#Product-type").val()}
})
.done(function(){
document.getElementById('lblStatus').innerHTML = "Result: <br/>"
document.getElementById('lblStatusContent').innerHTML = "Success!"
})
.fail(function(req, textStatus, errorThrown) {
document.getElementById('lblStatus').innerHTML = "Result: <br/>"
alert("Something went wrong!:" + textStatus + ' ' + errorThrown )
});
});
});
It's not possible to download files to your computer via an ajax (XHR) request. So you need to redirect the user actually (setting window.location) to a view that downloads the file. Or you can add as a result of the successful POST a button the current page so the user can download the file. In any case, you need to move the file download to a different view so a standard GET request can fetch it.
But your code to return the file in Django (using FileResponse) is correct.
There's also an explanation with an alternative way of doing it here
def validate(request):
if request.method == 'POST':
filename = request.POST.get('source_file')
file_path = os.path.join(settings.MEDIA_ROOT, 'SourceFiles', filename)
region = request.POST.get('region')
product_type = request.POST.get('product_type')
result = validateSource.delay(file_path, region, product_type)
output_filepath, log_filepath = result.get()
if os.path.exists(output_filepath) and os.path.exists(log_filepath):
zip_filename = zipFiles([output_filepath, log_filepath], filename)
zip_filepath = os.path.join(settings.MEDIA_ROOT, zip_filename)
with open(zip_filepath, 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/force-download")
response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(zip_filepath)
return response
raise Http404