How to send file with react and django rest - javascript

How can I send an image file from react to django.
I am new to react and django , currently I am being successful in sending and getting data from/to the endpoints, now I want to send an image file or any other file from react to django or get image file from django to react.I wrote some code but its not working properly and i am facing quite difficulty to send file, I researched but not get any useful link.Kindly can someone share link from where I can get better understanding how it works.Here below is my try:
REACT PART
let doc=new JsPDF();
doc.addImage(img,'JPEG',30,30);
//doc.save('test.pdf');
let formdata=new FormData();
formdata.append('file',doc);
fetch(`http://127.0.0.1:8000/chauffeur/pdf_upload/`,
{
method: 'POST',
body:formdata,
}
).then(response => response.json()).catch(error => console.error('Error:', error));
DJANGO PART
class PdfUpload(APIView):
parser_classes = (MultiPartParser, FormParser,)
def get(self, request):
return Response([PdfSerializer(file).data for file in Pdf.objects.all()])
def post(self,request):
payload=(request.data,request.FILES)
print("Hello")
print(payload)
serializer=PdfSerializer(data=payload)
if serializer.is_valid():
serializer.save()
return Response("File Saved in Backend",status=status.HTTP_201_CREATED)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
But I am getting too many errors from above code, like no file submitted or expected dict but receive list, can someone fix above code or can share helpful links from where I can understand better.Thanks in advance!

If the name of object in your models.py is for example PdfModel write like this:
from django.core.files import File
def post(self, request):
my_file = File(request.data.get('file'))
new_pdf_file = PdfModel.objects.create(
field1=request.data.get('field1'),
field2=request.data.get('field2'),
field3=my_file )
new_pdf_file.save()
return Response({"something","something")

Related

Connect views.py to a Javascript file

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.

Display a picture saved in HTML into a Vue.js page

I am currently trying to display a local picture saved in HTML into my Vue.js page.
I have tried to load the content of the HTML file into a variable using the following lines:
computed: {
compiledHtml: function() {
return this.asset;
}
const path = 'http://localhost:5000/load_results'
axios
.get(path)
.then((res) => {
this.asset = res.data
})
Then I have tried to display it using v-html:
<div v-html="compiledHtml"></div>
It actually works with a simple HTML file which contains a few lines, for example:
<h1> test load HTML file </h1>
However, my picture size is 3.5Mb and is much more complex than the example I gave you and when I try to display it, it gives me a blank space.
Is there anyone who knows how to overcome this problem? Thanks.
Here is the GET method I have used:
#bp.route('/load_results', methods=['GET'])
def load():
f = codecs.open("./file.html", 'r', 'utf-8')
return f.read()
I have successfully overcome this problem by modifying my GET method to open the file inside my API like this :
import webbrowser
#bp.route('/load_html_picture_file', methods=['GET'])
def load():
webbrowser.open(path_to_file)
Therefore it open my image in a new tab in my webbrowser.
Thanks anyway.

Render template in Django view after AJAX post request

I have managed to send & receive my JSON object in my views.py with a POST request (AJAX), but am unable to return render(request, "pizza/confirmation.html"). I don't want to stay on the same page but rather have my server, do some backend logic on the database and then render a different template confirming that, but I don't see any other way other than AJAX to send across a (large) JSON object. Here is my view:
#login_required
def basket(request):
if request.method == "POST":
selection = json.dumps(request.POST)
print(f"Selection is", selection) # selection comes out OK
context = {"test": "TO DO"}
return render(request, "pizza/confirmation.html", context) # not working
I have tried checking for request.is_ajax() and also tried render_to_string of my html page, but it all looks like my mistake is elsewhere. Also I see in my terminal, that after my POST request, a GET request to my /basket url is called - don't understand why.
Here is my JavaScript snippet:
var jsonStr = JSON.stringify(obj); //obj contains my data
const r = new XMLHttpRequest();
r.open('POST', '/basket');
const data = new FormData();
data.append('selection', jsonStr);
r.onload = () => {
// don't really want any callback and it seems I can only use GET here anyway
};
r.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
r.send(data);
return false;
In your basket view function, you always render the template as response. You can pass the parameters to your js snippet via HttpResponse. After request completed and you have response in your js function, you can use window.location.href to redirect the page you want. You can also look this answer to get more information.

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)) }}

Rendering Jinja template in Flask following ajax response

This is my first dive into Flask + Jinja, but I've used HandlebarsJS a lot in the past, so I know this is possible but I'm not sure how to pull this off with Flask:
I'm building an app: a user enters a string, which is processed via python script, and the result is ajax'd back to the client/Jinja template.
I can output the result using $("body").append(response) but this would mean I need to write some nasty html within the append.
Instead, I'd like to render another template once the result is processed, and append that new template in the original template.
Is this possible?
My python:
from flask import Flask, render_template, request, jsonify
from script import *
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/getColors')
def add_colors():
user = request.args.get("handle", 0, type = str)
return jsonify(
avatar_url = process_data(data)
)
if __name__ == '__main__':
app.run()
There is no rule about your ajax routes having to return JSON, you can return HTML exactly like you do for your regular routes.
#app.route('/getColors')
def add_colors():
user = request.args.get("handle", 0, type = str)
return render_template('colors.html',
avatar_url=process_data(data))
Your colors.html file does not need to be a complete HTML page, it can be the snippet of HTML that you want the client to append. So then all the client needs to do is append the body of the ajax response to the appropriate element in the DOM.

Categories

Resources