How to check file arrived in JavaScript and HttpResponse object in Django - javascript

My code is working fine, but I can't figure out how to catch a file arrives message in JavaScript.
I'm working with Django 2.1.
Template:
...
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
...
<input type="file" id="prd" name="prd" required>
</div>
...
<input id="btn_ini" type="submit" name="submit" value="Init process">
</form>
...
<script type="text/javascript">
document.addEventListener('???', function(){
// I wish indicate to the user that the process is runnning and don't close the page.
// at the moment the logic is working as spected but I can't achieve how to check in javascript when file arrives.
})
</script>
</body>
</html>
Views:
def add_destination(request):
...
if request.method == 'POST':
...
return handle_uploaded_file(prd)
return render(request, 'add-destination.html')
def handle_uploaded_file(f)
...
file = # processing file
...
with open(file, 'rb') as f:
file_data = f.read()
response = HttpResponse(
file_data, content_type='application/force-dowload')
response['Content-Disposition'] = 'attachment; filename="proc_{}"'.format(incoming_file_name)
return response
return None

After read some books and many test, I found a solution
All backend code has no changes and only I improved the javascript code
<script type="text/javascript">
const form = document.querySelector('form');
const url = '{% url "app:index" %}';
const loading = document.querySelector('.loading');
let objUrl = null;
form.submit = async e => {
e.preventDefault()
// ...
const formData = new FormData(e.target);
// fetch file from server
const result = await fetch(url,{
method:'POST',
data:formData
})
// convert it to blob
const blob = await result.blob()
// Create obj locally
objUrl = URL.createObjectURL(blob)
//revoke url
URL.revokeObjectURL(blob)
// ....
}
When client submit Form, everythings works as expected.
The browser open it dialog automatically when file arrive after my processes done at server side.

Related

Flask doesnt'see uploaded file

I have this simple html:
<input class="input" type="file" name="file" id="imageInp"></input>
<button class="addBtn" id="addBtn">Add</button>
And this JS:
var HttpClient = function () {
this.get = function (aUrl, img) {
var anHttpRequest = new XMLHttpRequest();
var fdata = new FormData();
fdata.append("file", img);
anHttpRequest.open("POST", aUrl, true);
anHttpRequest.setRequestHeader("Content-type", "multipart/form-data");
anHttpRequest.send(fdata);
}
}
document.getElementById("addBtn").onclick = function() {
image = document.getElementById("imageInp").files[0];
var client = new HttpClient();
client.get(*url_here*, image);
}
And this code in flask:
#app.route('*url_here*', methods=['POST'])
def foo():
try:
print(request.form)
print(request.files)
print(request.data)
frame = request.files['file'].read()
return 'OK', 200, {'ContentType':'application/json'}
except Exception as e:
log('Main', e)
return 'Error', 400, {'ContentType':'application/json'}
And when I use that all I see this:
ImmutableMultiDict([])
ImmutableMultiDict([])
b''
400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
So, flask doesn't see my file. How can I fix it? Thanks in advance.
Found solution here: Upload files to Flask server via xhr
It's strange. I saw another questions where people recommended using this header.

Getting image from a input field with Javascript to parse it to an API?

Currently trying to make use of an image upload class I created in php that saves an image to a folder and a text file but I want to save it from an api that I call in Javascript instead of by submitting a form.
Here I am trying to call the api
async function createTweet(e) {
const id = document.getElementById('user-id').getAttribute('data-user-id');
const tweet = e.target.parentNode.parentNode.querySelectorAll('input')[1]
.value;
const image = e.target.parentNode.parentNode.querySelectorAll('input')[0];
console.log(image);
const data = new FormData();
data.append('userId', id);
data.append('tweet', tweet);
data.append('tweet-image', image);
try {
const conn = await fetch('php/api/api-create-tweet.php', {
method: 'POST',
body: data,
});
const res = await conn.text();
getData();
// TODO show user he has created a tweet
} catch (error) {
console.log(error);
}
}
Just wondering what I can do with the image so I can read the file in my api with $_FILES['tweet-image'] and if I need to do anything to the form data to make it form type enctype
The code should work with some changes. You have two ways of doing it (see FormData # developer.mozilla.org):
Let's say you have a simple form:
<!-- just an example -->
<form method="post" action="form.php" enctype="multipart/form-data">
<input type="text" name="tweet" />
<input type="file" name="image" />
<input type="submit" />
</form>
<script>
/* prevent sending the form */
var form = document.forms[0];
form.onsubmit = function(e) {
e.preventDefault();
sendForm();
}
</script>
A. importing the <form> directly into FormData():
<script>
async function sendForm() {
// import form input here ->
const data = new FormData(form);
const conn = await fetch('form.php', {
method: 'POST',
body: data
});
const res = await conn.text();
}
</script>
B. make sure you actually append the .files[0] from the input[type="file"] into the formData():
<script>
async function sendForm() {
const data = new FormData();
const tweet = form["tweet"].value;
// notice the use of .files[0] -->
const image = form["image"].files[0];
data.append("tweet", tweet);
data.append("image", image);
const conn = await fetch('form.php', {
method: 'POST',
body: data
});
const res = await conn.text();
}
</script>
Then in your PHP file you should be able to access both $_POST["tweet"] (text) and $_FILES["image"] (file) in this example.

Uploading Binary file (Dicom file) to flask server and receiving JSON response at the same time using javascript

I'm trying to upload a dicom file to a flask server that runs a deep learning model and get the predicted values from the server as in JSON format!
so the problem is in the javascript code below. is there a way to do both sending and getting values at the same time? please Help!!
HTML:
<body>
<input id="image-selector" type="file">
<button id="predict-button">Predict</button>
<p><h1>PREDICTIONS</h1></p>
<span id="predicted-value_1">
<span id="predicted-value_2">
<span id="predicted-value_3">
</body>
JavaScript
$("#predict-button").click(function(){
var form_data = new FormData();
var ins = document.getElementById('image-selector').files.length;
if(ins == 0) {
$('#msg').html('<span style="color:red">Select one file</span>');
return;
}
else{
form_data = document.getElementById('image-selector').files[0]
}
let message = {
"file": form_data
}
console.log(message);
$.post("http://127.0.0.1:5000/predict", JSON.stringify(message), function(response){
$("#predicted-value_1").text(response.prediction.value1);
$("#predicted-value_1").text(response.prediction.value2);
$("#predicted-value_1").text(response.prediction.value3);
console.log(response);
});
});
Python
#app.route("/predict", methods=['GET', 'POST'])
def predict():
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
# if user does not select file, browser also
# submit an empty part without filename
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
#Rest of the code! I can take it from here!!
I did something like this in my flask demo. You can have a look and give a try.
HTML
<h4>Welcome to ImageClassifier Demo</h4>
<input type=text size=5 name=url>
<button id="prediction" type="submit">
<span>Predict</span>
</button>
<span id=result>
Result:
</span>
js
<script type="text/javascript">
$(document).ready(function(){
$('#prediction').bind('click', function() {
$.getJSON('/predict', {
a: $('input[name="url"]').val()
}, function(data) {
console.log("Result Received")
$("#result").text("Result: " + data.result);
});
return false;
});
});
</script>

CSRF validation failed when integrate CKeditor to Flask

I am integrating CKeditor to Flask to add rich text support. But when file upload feature is enabled, the post request is always failed. It should be the csrf problem. Added {{csrf_token()} directly doesn't work. Is there anyplace in CKeditor should be changed to add csrf?
{% block content %}
<h1>Add articile:</h1>
<form>
<input type="hidden" name="csrf_token" value="{{csrf_token()}}" />
<textarea name="editor1" id="editor1" rows="20" cols="80">
This is my textarea to be replaced with CKEditor.
</textarea>
<script type="text/javascript">
CKEDITOR.replace('editor1', {
filebrowserUploadUrl: '/ckupload',
});
</script>
</form>
{% endblock %}
To handle file upload,
def gen_rnd_filename():
filename_prefix = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
return '%s%s' % (filename_prefix, str(random.randrange(1000, 10000)))
#app.route('/ckupload', methods=['POST', 'OPTIONS'])
def ckupload():
"""CKEditor file upload"""
error = ''
url = ''
callback = request.args.get("CKEditorFuncNum")
print callback
print request.method
if request.method == 'POST' and 'upload' in request.files:
fileobj = request.files['upload']
fname, fext = os.path.splitext(fileobj.filename)
rnd_name = '%s%s' % (gen_rnd_filename(), fext)
filepath = os.path.join(app.static_folder, 'upload', rnd_name)
dirname = os.path.dirname(filepath)
if not os.path.exists(dirname):
try:
os.makedirs(dirname)
except:
error = 'ERROR_CREATE_DIR'
elif not os.access(dirname, os.W_OK):
error = 'ERROR_DIR_NOT_WRITEABLE'
if not error:
fileobj.save(filepath)
url = url_for('static', filename='%s/%s' % ('upload', rnd_name))
else:
error = 'post error'
res = """<script type="text/javascript">
window.parent.CKEDITOR.tools.callFunction(%s, '%s', '%s');
</script>""" % (callback, url, error)
response = make_response(res)
response.headers["Content-Type"] = "text/html"
return response
Current my workaround is to add csrf exception to this url.
#csrf.exempt
CKEditor use AJAX to send uploads, so you can add CSRF support in this way:
<script type="text/javascript">
CKEDITOR.replace( "textarea-name", {
fileTools_requestHeaders: {
'X-CSRFToken': '{{ csrf_token() }}',
},
});
</script>
BTW, I recommend use Flask-CKEditor to integrate CKEditor with Flask-WTF, it makes this usage easier:
from flask_wtf import CSRFProtect
app = Flask(__name__)
# the secret key used to generate CSRF token
app.config['SECRET_KEY'] = 'dev key'
# enable CSRF protection
app.config['CKEDITOR_ENABLE_CSRF'] = True
csrf = CSRFProtect(app)

django view cannot get file using request.FILES from ajax form submit

I tried to submit this form using ajax ,sothat a django view can extract the selected file from request.FILES and write to a directory on server
<form enctype="multipart/form-data" method="post" id="fileupoadform">{% csrf_token %}
<p>
<label>Select a file
<input type="file" name="fselect" id="fselect"> </input>
</label>
</p>
<input type="submit" value="upload">
</form>
the view is
def ajax_upload(request):
print 'ajax_upload()'
print 'request=',request
to_return = {}
store_message="failure"
if (request.is_ajax()) and (request.method == 'POST'):
print 'is ajax and post'
print 'request.FILES=',request.FILES
if request.FILES.has_key('fselect'):
print "request has key='fselect'"
file = request.FILES['fselect']
with open(settings.UPLOADPATH'%s' % file.name, 'wb+') as dest:
for chunk in file.chunks():
dest.write(chunk)
store_message="success"
to_return['store_message']= store_message
print 'to_return=',to_return
to_return['store_message']= store_message
serialized = simplejson.dumps(to_return)
print 'serialized=',serialized
if store_message == "success":
print 'suceessfully returning'
return HttpResponse(serialized, mimetype="application/json")
else:
print 'failed!! returning'
return HttpResponseServerError(serialized, mimetype="application/json")
I used jquery to make the ajax submit
$(document).ready(function(){
$('#fileupoadform').submit(function(e){
submitUploadForm(e);
});
});
function submitUploadForm(e){
console.log('clicked submit');
e.preventDefault();
var file = $('#fselect').get(0).files[0];
console.log('filename='+file.name)
var data = { name:file.name };
var args = { type:"POST", url:"upload/", data:data, complete:doneAjaxUpload };
$.ajax(args);
}
when I tried this ,I got this console output
ajax_store_uploaded_file()
request= <WSGIRequest
GET:<QueryDict: {}>,
POST:<QueryDict: {u'name': [u'myfile.srt']}>,
COOKIES:{'csrftoken': 'ca367878345fa9e59adf79hg047a1dvb'},
...
is ajax and post
request.FILES= <MultiValueDict: {}>
to_return= {'store_message': 'failure'}
serialized= {"store_message": "failure"}
failed!! returning
[01/Jun/2012 11:27:26] "POST /myapp/upload/ HTTP/1.1" 500 28
I sense that I am doing something wrong in the django view..Is it that I cannot get the uploaded file from request.FILES.In a non ajax version of django view ,I was able to get the file from request.FILES using request.FILES['fselect']
Can somebody help me resolve this?
I don't think you can do ajax file uploads (easily).
Certainly, it doesn't look like you're actually passing a file to your post data, you're just passing the file name -
var data = { name:file.name };
Check out this question for plugins / info to help do this - How can I upload files asynchronously?

Categories

Resources