Connect views.py to a Javascript file - javascript

I'm working on a Django project showing PDF files from a dummy database. I have the function below in views.py to show the PDF files.
def pdf_view(request):
try:
with open ('static/someData/PDF', 'rb') as pdf:
response = HttpResponse(pdf.read(), content_type="application/pdf")
response['Content-Disposition'] = 'filename=test1.pdf'
return response
pdf.closed
except ValueError:
HttpResponse("PDF not found")
This function needs get connected to another function located in a javascript file.
How do we connect views.py to another Javascript file?

Finally, I added an "Iframe tag" in the JavaScript file. Then there was no need to use the "def pdf_view(request)" function.

Related

Flask send_file done with JavaScript [duplicate]

This question already has answers here:
Return a download and rendered page in one Flask response
(2 answers)
Closed 6 months ago.
I have this flask app route:
#app.route('/generatecleanbudgetfile', methods=['GET', 'POST'])
def clean_budget():
file = request.files.get('data_file')
app.logger.info('Budget Formatting request has started')
try:
if request.method == 'POST':
file = request.files.get('data_file')
file.seek(0)
buffer = budget_cleaner(file)
buffer.seek(0)
app.logger.info('Conversion Complete')
return send_file(
buffer,
as_attachment=True,
attachment_filename=f'stripped_budget_{dt.today().strftime("%m.%d.%Y")}.xlsx',
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
except:
app.logger.error(f"Budget formatting failed on {file}")
return render_template('error_type.html', title='Unable to process uploaded budget')
My html:
{% extends "base.html" %}
{% block head %}
{% endblock %}
{% block content %}
<div id="vo_budget_file_settings">
{# Upload Final CRO Budget File #}
<p id="uploadPara">Please upload the final CRO budget File</p>
<form class="" action="/generatecleanbudgetfile" method=POST enctype=multipart/form-data>
<input type="file" name="data_file" accept=".xls, .xlsx, .xlsm"/>
<input type="submit" value="Begin Format" onclick="loading();"/>
</form>
</div>
<!-- funtion to show css spinner on button click -->
<script type="text/javascript">
function loading(){
$(".loader").show();
}
</script>
I understand that flask cannot both render_template and send_file since it can only return a single item.
Question:
How would I go about downloading a file via JavaScript instead so I could use my return to render a new template?
I'm wanting to replace this piece:
return send_file(
buffer,
as_attachment=True,
attachment_filename=f'stripped_budget_{dt.today().strftime("%m.%d.%Y")}.xlsx',
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
To download the file with JS, you could encode it and include it in your template as a string literal inside a JS Blob object, then save that Blob as soon as the page renders. Something like this in your template for success, where you pass your encoded file contents into the file_contents template variable:
<body>
Page content here
<script>
const myBlob = new Blob(["{{file_contents}}"], {type:"your-file's-mime-type"})
// then google "how to save js blob to local file".
// This other post might help: https://stackoverflow.com/questions/25547475/save-to-local-file-from-blob
</script>
</body>
To further illustrate as an example, making a blob that has the plaintext contents "Hello World" would go like new Blob(["Hello World"], {type:"text/plain"}). Your case might be more complicated if you file type isn't plaintext or has a weird encoding, but this is the general idea.
Another (probably less hack-y) idea would be do the same Blob thing except use JS's native fetch API to get the file contents from your server to the Blob instead of passing it through the template. This is similar to the other answer that suggested saving the file on the server, except instead of providing an a tag you just do the download in pure JS.
Flask can't do both things(render & send file) in a single request.
But you can have an alternative solution↓
In your generatecleanbudgetfile request:
Generate a file and save it in server
Provide a file link in your html
just render_template in this request
So, when the user get the response, they can click on download link to retrieve the file generated in the first step.

How to use information sended by the controller in a JavaScript file using Spring Boot?

I'm using Spring Boot with the Thymeleaf template engine. I have a HTML called clients.html file in the templates folder and a JavaScript file called functions.js in the static folder. I want to send from the controller to the JavaScript file a List.
I have tried using this syntax in the JavaScript file:
let listaArticulos = /*[[${numeroArticulos}]]*/ [];
But I don't recive anything. I have tried using the script tag in the HTML and it worked, but I want to have the JS code in a separate file and not in a script tag with all my html code.
The controller where I send the information to the JS looks like this:
#GetMapping("/articulos")
public ModelAndView showHielo(#RequestParam(name = "numcli", required = false) String numcli){
ModelAndView mav = new ModelAndView(ViewConstant.ARTICULOS);
mav.addObject("numeroArticulos", searchMovimNumarts(" 133"));
return mav;
}
Where the controller send the searchMovimNumarts() method with the name of "numeroArticulos" the one returns a List.
And the JS file where I want to recive the "numeroArticulos" object looks like this:
/*This variable stores data sended by the controller*/
let listaArticulos = /*[[${numeroArticulos}]]*/ [];
console.log(listaArticulos);
I want to console log the content of the List using a JS file and no the html
tag. How can I solve this?
Thymeleaf template engine parses only the template file(html files). So you have to include those variables defined in the controller into the embedded js code. However You don't have to put your entire js code in your html. Have only that part of code that refer to those variables in script tag.
<script>
let listaArticulos = /*[[${numeroArticulos}]]*/ [];
</script>
and refer them in your external js after this
<script src="/js/externalscript.js"></script>

Dropzone.js prevents Flask from rendering template

I am using Dropzone.js to allow drag and drop upload of CSV files via a Flask web site. The upload process works great. I save the uploaded file to my specified folder and can then use df.to_html() to convert the dataframe into HTML code, which I then pass to my template. It gets to that point in the code, but it doesn't render the template and no errors are thrown. So my question is why is Dropzone.js preventing the render from happening?
I have also tried just return the HTML code from the table and not using render_template, but this also does not work.
init.py
import os
from flask import Flask, render_template, request
import pandas as pd
app = Flask(__name__)
# get the current folder
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
#app.route('/')
def index():
return render_template('upload1.html')
#app.route('/upload', methods=['POST'])
def upload():
# set the target save path
target = os.path.join(APP_ROOT, 'uploads/')
# loop over files since we allow multiple files
for file in request.files.getlist("file"):
# get the filename
filename = file.filename
# combine filename and path
destination = "/".join([target, filename])
# save the file
file.save(destination)
#upload the file
df = pd.read_csv(destination)
table += df.to_html()
return render_template('complete.html', table=table)
if __name__ == '__main__':
app.run(port=4555, debug=True)
upload1.html
<!DOCTYPE html>
<meta charset="utf-8">
<script src="https://rawgit.com/enyo/dropzone/master/dist/dropzone.js"></script>
<link rel="stylesheet" href="https://rawgit.com/enyo/dropzone/master/dist/dropzone.css">
<table width="500">
<tr>
<td>
<form action="{{ url_for('upload') }}", method="POST" class="dropzone"></form>
</td>
</tr>
</table>
EDIT
Here is the sample csv data I am uploading:
Person,Count
A,10
B,12
C,13
Complete.html
<html>
<body>
{{table | safe }}
</body>
</html>
Update: Now you can use Flask-Dropzone, a Flask extension that integrates Dropzone.js with Flask. For this issue, you can set DROPZONE_REDIRECT_VIEW to the view you want to redirect when uploading complete.
Dropzone.js use AJAX to post data, that's why it will not give back the control to your view function.
There are two methods to redirect (or render template) when all files were complete uploading.
You can add a button to redirect.
Upload Complete
You can add an event listener to automatic redirect page (use jQuery).
<script>
Dropzone.autoDiscover = false;
$(function() {
var myDropzone = new Dropzone("#my-dropzone");
myDropzone.on("queuecomplete", function(file) {
// Called when all files in the queue finish uploading.
window.location = "{{ url_for('upload') }}";
});
})
</script>
In view function, add an if statement to check whether the HTTP method was POST:
import os
from flask import Flask, render_template, request
app = Flask(__name__)
app.config['UPLOADED_PATH'] = 'the/path/to/upload'
#app.route('/')
def index():
# render upload page
return render_template('index.html')
#app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
for f in request.files.getlist('file'):
f.save(os.path.join('the/path/to/upload', f.filename))
return render_template('your template to render')
Your code does work. Your template will be rendered and returned.
Dropzone will upload files you drag and drop into your browser 'in the background'.
It will consume the response from the server and leave the page as is. It uses the response from the server to know if the upload was successful.
To see this in action:
Navigate to your page
Open up your favourite browser dev tools; (in firefox press CTRL+SHIFT+K)
Select the network tab
Drag your csv into the dropzone pane and note that the request shows in the dev tools network table
Here is a screen shot from my browser. I copied your code as is from your question.
To actually see the rendered complete.html you will need to add another flask endpoint and have a way to navigate to that.
For example:
in upload1.html add:
Click here when you have finished uploading
in init.py change and add:
def upload():
...
# you do not need to read_csv in upload()
#upload the file
#df = pd.read_csv(destination)
#table += df.to_html()
return "OK"
# simply returning HTTP 200 is enough for dropzone to treat it as successful
# return render_template('complete.html', table=table)
# add the new upload_complete endpoint
# this is for example only, it is not suitable for production use
#app.route('/upload-complete')
def upload_complete():
target = os.path.join(APP_ROOT, 'uploads/')
table=""
for file_name in os.listdir(target):
df = pd.read_csv(file_name)
table += df.to_html()
return render_template('complete.html', table=table)
If you are using Flask-Dropzone then:
{{ dropzone.config(redirect_url=url_for('endpoint',foo=bar)) }}

How to stream data from python to javascript

I am looking for a way to stream data from python script to a javascript within a html file.
My data is stored in a large csv file which looks like:
x1,x2,y1,y2
0.5,0.54,0.04,0.55
0.12,0.88,1.02,0.005
...
...
The python script must pre-process this data before sending it to javascript:
import csv
def send_data(filename):
with open(filename, "rb") as csvfile:
datareader = csv.reader(csvfile)
for row in datareader:
preprocessed = Do_something(row)
yield preprocessed
The javascript should process the received data from the python script above.
Without knowing more about your exact requirements you could do something like this using circuits:
Code: (untested)
import csv
from circuits.web import Server, Controller
def Do_something(row):
return row
class Root(Controller):
def send_data(self, filename):
self.response.stream = True
with open(filename, "rb") as csvfile:
datareader = csv.reader(csvfile)
for row in datareader:
preprocessed = Do_something(row)
yield preprocessed
app = Server(("0.0.0.0", 8000))
Root().register(app)
app.run()
Then requests to http://localhost:8000/send_data/filename would result in a stream resolve of the entire csv file. This also assumes you actually want to serve up the csv file as a web response to some web application.

How to use rails method in .js.erb and pass it javascript argument?

I have a .js.erb file and I'm trying to make it possible to write comments. I have two tabs: write and preview. When you click on 'preview' tab, markdown preview should be displayed. Now, I'm using Redcarpet and stuff from RailsCast272, so my markdown function is in application_helper.rb file:
def markdown(text)
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML)
return markdown.render(text).html_safe
end
How to I use it in .js.erb file and pass it a value of a tag? I get error "undefined local variable or method `markdown'"?
Thanks

Categories

Resources