Upload an canvas image dataUrl to flask app - python

I'm new to flask and jquery. I'm uploading data url that i captured from a video element using the following code in js/jquery
click_button.addEventListener('click', function() {
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
video.style.display = "none";
let image_data_url = canvas.toDataURL('image/jpeg');
dataurl.value = image_data_url;
dataurl_container.style.display = 'block';
$.ajax({
type: "POST",
url: "http://127.0.0.1:5000/uploader",
data: {
imgBase64: image_data_url
}
}).done(function(o) {
console.log('saved');
});
video.pause()
});
flask code that is reading the data
#app.route('/uploader', methods=['GET', 'POST'])
def upload_file_method():
if request.method == 'POST':
f = request.files['file']
f.save(secure_filename(f.filename))
resp = sendReq(f.filename,url="http://someurl")
print(resp.json())
return 'file uploaded successfully'
The request.files['file'] is empty or not available. How to read the data sent from jquery above? request.data is empty as well.

Related

Django: ajax not returning or sending any data in django

i am creating a simple like button with ajax, i have followed the tutorial but it seems, that i am missing something, i am not getting any error either in the console in my django terminal but when i click the button no data get sent, evrything just remains the same way, and this is not what i am expecting, i know i am missing something somewhere and i cannot really tell where this error is coming from.
views.py
#login_required
def like(request):
if request.POST.get("action") == 'post':
result = ""
id = int(request.POST.get('courseid'))
course = get_object_or_404(Course, id=id)
if course.like.filter(id=request.user.id).exists():
course.like.remove(request.user)
course.like_count -= 1
result = course.like_count
course.save()
else:
course.like.add(request.user)
course.like_count += 1
result = course.like_count
course.save()
return JsonResponse({'result': result})
urls.py NOTE:I don't know if i need a slug in this url path
path('like/', views.like, name="like"),
base.html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
course-detail.html
<li><button id="like-button" value="{{course.id}}">like</button><span id="like-count">{{course.llke_count}}</span></li>
<script type="text/javascript">
$(document).on("click", '#like-button', function(e){
e.preventDefault()
$.ajax({
type: 'POST',
url: '{% url 'course:like' course.slug %}',
data: {
courseid: $('#like-button').val(),
csrfmiddlewaretoken: $("input[name=csrfmiddlewaretoken]").val(),
action: 'post'
},
success: function(json){
document.getElementById("like-count").innerHTML = json['result']
console.log(json)
},
error: function (xhr, errmsg, err)
console.log(xhr)
console.log(errmsg)
console.log(err)
})
})
</script>
this is all the code i have written for the functionality, if there is any other thing to be provided i will update the question
UPDATE AFTER FIRST ANSWER
#####################################################################
Now when i click the like button is does show an visible error but the like count now shows undefined and in my chrome dev tools is shows failed to load response data because this request was redirected
Update your code like this and I've doubt about your like table provide that inside your question.
inside your views.py
#login_required
def like(request):
if request.method == 'POST':
result = ""
course_id = int(request.POST.get('courseid'))
course = get_object_or_404(Course, id=course_id)
if course.like.filter(id=request.user.id).exists():
course.like.remove(request.user)
course.like_count -= 1
result = course.like_count
course.save()
else:
course.like.add(request.user)
course.like_count += 1
result = course.like_count
course.save()
return JsonResponse({'result': result})
inside your course-detail.html
<script type="text/javascript">
$("#like-button").on("click", function (e) {
e.preventDefault()
$.ajax({
type: 'POST',
url: "{% url 'course:like' %}",
data: {
courseid: $('#like-button').val(),
csrfmiddlewaretoken: "{{ csrf_token }}",
},
success: function (json) {
document.getElementById("like-count").innerHTML = json['result']
console.log(json)
},
error: function (xhr, errmsg, err) {
console.log(xhr)
console.log(errmsg)
console.log(err)
}
})
})
</script>
Note :
You don't have to check for action instead you can check for method eg. request.method.
You've provided wrong url inside your ajax call '{% url 'course:like' course.slug %}' it should be '{% url 'course:like' %}' without passing slug.
Do not use id as avariable because it will conflict with python id() function, you can check for all available built-in functions in python here.

Flask, how to correctly upload CSV?

I'm creating an app where the client upload a CSV file and the server doesn't store it but only read it to perform tasks and return the content of the CSV as a JSON.
I followed some tutorials and posts and I came to this code:
Flask:
#app.route('/analyse_dataset', methods=['GET','POST'])
def analyse_dataset_route():
print('/analyse_dataset called', file=sys.stderr)
try:
# check if the post request has the dataset part
if 'file' not in request.files:
data = {'error': 'Dataset not in requested files'}
return Response(data, status=400, mimetype='application/json')
print('request.files : ' + str(request.files))
uploaded_file = request.files['file']
# no dataset
if uploaded_file.filename == '':
logger.debug('Dataset not found, returning to /')
return redirect('/')
# dataset ok
if uploaded_file:
print('uploaded_file ok', file=sys.stderr)
filename = secure_filename(uploaded_file.filename)
#uploaded_file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
uploaded_file.stream.seek(0)
myfile = uploaded_file.file
print('uploaded_file name: ' + filename, file=sys.stderr)
dataframe = pd.read_csv(myfile)
return Response(dumps(dataframe), status=200, mimetype='application/json')
else:
data = {'error': 'Something went wrong...'}
return Response(data, status=400, mimetype='application/json')
except Exception as e:
logger.error('An error occurred while analysing dataset')
logger.error(e, exc_info=True)
print(e)
data = {'error': 'An error occurred while analysing dataset'}
return Response(data, status=400, mimetype='application/json')
client side:
onClickHandler = () => {
if (this.state.selectedFile == null) {
toast.error('No file selected')
} else {
const data = new FormData()
data.append('file', this.state.selectedFile)
let req = "http://localhost:5001/analyse_dataset"
axios.post(req, data, {
onUploadProgress: ProgressEvent => {
this.setState({
loaded: (ProgressEvent.loaded / ProgressEvent.total * 100),
loading: true
})
},
})
.then(res => { // then print response status
console.log("file processed: " + res.data)
this.setState({
redirect: true,
jsondata: res.data
})
})
.catch(err => { // then print response status
console.log(err)
this.setState({
selectedFile: null,
loaded: 0,
loading: false
})
setTimeout(() => {
toast.error("Process failed, be sure to upload a correct file.")
}, 500)
})
}
}
So there is this issue where it's "" working "" with a large CSV file but it isn't working with a smaller one and I can't figure out why. Also I'd like to return a JSON containing each line of the CSV to the client but for the moment it isn't working aswell.
Here is the error :
Your code is likely failing on myfile = uploaded_file.file. Try changing the line to myfile = uploaded_file.stream.
If you are using Python 3, then pandas.read_csv requires text file/stream i.e. unicode. Convert the stream and it should work.
myfile = io.StringIO(myfile.getvalue().decode())
Once you have your pd.DataFrame object, you can use pd.DataFrame.to_json to convert your files. See the docs here.
I am unsure as to exactly why larger files work.

Bad request Json to Flask ajax

My Jquery code:
var obj_submit = {
email_p : $($('.form-group').find("input[name='email_p']")[0]).val(),
email_a : $($('.form-group').find("input[name='email_a']")[0]).val()
}
var json_submit = JSON.stringify(obj_submit);
$.ajax({
type: 'GET',
url: url,
contentType: 'application/json',
dataType: 'json',
data: json_submit
My python code:
`#app.route('/admission', methods=["GET", "POST"])
def admission():
form = FormFieldsAdmissao()
print (request.is_json)
content = request.get_json()
print (content)
return 'JSON posted'`
in the browser console I receive: GET [...] 400 (BAD REQUEST)
(the number of questions on the same subject is impressive, it makes me think it was something that should be simpler, since everyone has questions about it)

Bottle POST method - getting query parameters

I am trying to send a POST AJAX request to a Bottle server and read query_string parameters.
This works with GET method, but with POST, bottle.request.query_string is empty.
This is with python 3.6.8. Bottle version in 0.12.17
I'm stuck, please advise.
Bottle server:
#!/usr/bin/env python3
import bottle
print(bottle.__version__)
class EnableCors(object):
name = "enable_cors"
api = 2
def apply(self, fn, context):
def _enable_cors(*args, **kwargs):
bottle.response.headers["Access-Control-Allow-Origin"] = "*"
bottle.response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, OPTIONS"
bottle.response.headers["Access-Control-Allow-Headers"] = "Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token"
if bottle.request.method != "OPTIONS":
return fn(*args, **kwargs)
return _enable_cors
application = bottle.app()
application.install(EnableCors())
#application.route("/api/params", method=['OPTIONS', 'POST'])
def Api_Params():
print('bottle.request.query_string:', bottle.request.query_string)
bottle.run(host='0.0.0.0', port=8080, debug=True, reloader=True)
Test javscript client:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<script>
function test_post_param() {
var data = {'e': 'E', 'f': 'F', 'g': {'aa':'AA', 'bb':'BB'}};
$.ajax({
url: 'http://127.0.0.1:8080/api/params',
method: "POST",
data: "key=a",
// contentType: "text/plain",
success: function (response, textStatus) {
console.debug("test_post_param OK");
console.debug(textStatus);
console.debug(response);
},
error: function (response, textStatus) {
console.debug("test_post_param ERR");
console.debug(textStatus);
console.debug(response);
},
})
}
window.onload = test_post_param;
</script>
</body>
</html>
I put this on all my API endpoints. I am combining the POST form and query encoding into a single dict.
def merge_dicts(*args):
result = {}
for dictionary in args:
result.update(dictionary)
return result
payload = merge_dicts(dict(request.forms), dict(request.query.decode()))
So your code would look like this:
#application.route("/api/params", method=['OPTIONS', 'POST'])
def Api_Params():
payload = merge_dicts(dict(request.forms), dict(request.query.decode()))
print('bottle.request.query_string: {}'.format(payload))
Here is an example sending the data as JSON to a POST route which I have used successfully.
The JQuery AJAX call:
function test_post_param() {
var data = {'e': 'E', 'f': 'F', 'g': {'aa':'AA', 'bb':'BB'}};
$.ajax({
url: 'http://127.0.0.1:8080/api/params',
method: "POST",
data: JSON.stringify({
"key": "a"
}),
cache: false,
contentType: "application/json",
dataType: "json",
success: function(data, status, xhr){
// Your success code
},
error: function(xhr, status, error) {
// Your error code
}
})
};
The Bottle route:
#application.route("/api/params", method=['POST'])
def Api_Params():
key = bottle.request.forms.get("key")
print(key) # This should print 'a'
I prefer from bottle import route, get, post, template, static_file, request as the import statement. This allows the route to be written more simply (in my opinion).
#post("/api/params")
def Api_Params():
key = request.forms.get("key")
print(key) # This should print 'a'

Download CSV file to the client

I have the following route:
#app.route('/download/', methods=['GET'])
def download():
output_filename = request.args.get('output_filename')
data = dict(foos=[1,2,3,3,2,1], bars=[7,7,7,7,7,7])
df = pd.DataFrame(data)
result = df.to_csv(index=False)
response = make_response(result)
response.headers['Content-Disposition'] = f'attachment; filename={output_filename}'
response.headers['Cache-Control'] = 'must-revalidate'
response.headers['Pragma'] = 'must-revalidate'
response.headers['Content-type'] = 'application/csv'
return response
which I'm calling with AJAX as follows:
function download(data, handler = null) {
let data = {output_filename: "foo.csv"};
let url = "/download/";
$.ajax({
type: "GET",
url: url,
data: data,
success: function(data) {
console.log('success');
},
});
}
However, nothing's appearing on the client side. Am I missing something here?
Im more familiar with node than ajax ( i had the same issue in nodejs which i fixed here on stackoverflow), but maybe this will help:
$.ajax({
async: false,
from How do I make jQuery wait for an Ajax call to finish before it returns?

Categories