Force Download existing JSON file instead of displaying it with Django - django

My webpage has a functionality that lets users request fairly large json files (3MB+) to be generated. The generation process takes some time and I send them an email with a download link once it is ready.
My problem is that clicking the download URL will open the content of the json file in the browser instead of starting a download dialog.
I have found this question: Serving .json file to download but the solution reserialize the json file into the response:
mixed_query = list(invoices) + list(pcustomers)
json_str = serializers.serialize('json', mixed_query))
response = HttpResponse(json_str, content_type='application/json')
response['Content-Disposition'] = 'attachment; filename=export.json'
As the JSON file already exists, I do not want to rewrite it entirely within the response. I just want users to download the already generated file.
How can I force the URL to start a download when reached?
I am using Django 3.1, with Python 3.6
Here is the email template sent to users once the download link is ready:
{% extends "emails/email_css.html" %}
{% block mail_content %}
<p>Hi, {{ username }}</p>
<p>Your export for {{ export_name }} is ready!</p>
<p>The file will be available for download for 2 days, or until you request a new export.</p>
<a class="download_button" type="button" href={{ download_url }}>Download</a>
{% endblock %}
Edit:
I also tried this solution How to download file using anchor tag <a> but the json file still gets shown in the browser instead of being downloaded.

I eventually found how to do it, by returning a FileResponse with as_attachment=True.
from django.http import FileResponse
def download_export(request):
response = FileResponse(open("path/to/file.json", 'rb'), as_attachment=True,
filename="file_name.json")
return response

Try adding the download property to the <a> tag. You can optionally specify a download filename or not.
Without filename:
<a class="download_button" type="button" href={{ download_url }} download>Download</a>
With filename:
<a class="download_button" type="button" href={{ download_url }} download="someJsonFile.json">Download</a>
See docs here for the download property. Also the related StackOverflow post here.

Related

Django - pass file path/URL from HTML to view in order to change the source of my video stream

I am fairly new to the Django and HTML world and and would like to be able to select a video file and then play it in an edited version (AI classification and some OpenCV editing).
At the moment, playing of a local file works in that way that the file path of my dummy video file is fixed in my script where I load the VideoStream.
However, I would like to be able to specify via HTML input which file to load.
I have the problem that I do not know how to pass the selected file.
Via urls, parameters can be passed, but I do not know how I can pass the path or URL of the video file as a parameter. Or can something like this be achieved via post requests and if so how?
Here are parts of my script (I don't use post request for this at the moment):
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input id="myFileInput" type="text">
<input class="button1" id="inputfield" name="upload" type="file" accept="video/*" onchange="document.getElementById('myFileInput').src = window.URL.createObjectURL(this.files[0]); document.getElementById('buttonStart').className = 'button'; this.form.submit()" value="Select a File"/>
</form>
The file path is stored in 'myFileInput'. But I could also get the file path through post request. Then I have the problem, that no class instance that I know where I could save that path and load it later.
<img id="demo" src="">
and the function for
function video_on() {
document.getElementById("demo").src = "{% url 'mask_feed' urlpath='path_I_would_like_to_pass' %}"; //
document.getElementById("wait").innerHTML = "Turning on. . . . .";
setTimeout(showText, 3000);
}
and the urls.py file:
path('mask_feed/<path:urlpath>', views.mask_feed, name='mask_feed'),
And of course I have a mask_feed method in my views.py that takes urlpath as argument.
How can I "insert" the file path I get with html insert into the Django template "{% url 'mask_feed' urlpath='path_I_would_like_to_pass' %}"?
I would like to do something like this:
document.getElementById("demo").src = "{% url 'mask_feed' urlpath='document.getElementById('myFileInput').src' %}"
But it doesn't work because of the quotation marks.
And if this is not the way to go, how should I do it?

Send an email html containing an image with webform in drupal 8

I have a webform form that sends emails in html format with attachments.
For that, I use the modules Mail System and Mime mail. Everything works well.
For the body of the mail I use the option Twig Template and again everything works well ... except that I can not put an image (a logo) in the body.
I tried a lot of things and nothing works!
Every time I find myself with an empty tag!
How to integrate the image of the logo into the body of my email?
Thanks for your help
I was able to include the Drupal logo without any problem using the below Twig template.
<img src="https://www.drupal.org/files/druplicon-small.png"/>
<hr/>
<p>Submitted on {{ webform_token('[webform_submission:created]', webform_submission) }}</p>
<p>Submitted by: {{ webform_token('[webform_submission:user]', webform_submission) }}</p>
<p>Submitted values are:</p>
{{ webform_token('[webform_submission:values]', webform_submission) }}
The img tag is not stripped out. My only guess is the image's src is not using an absolute URL

Generating download link in djano

I have referred to multiple django question regarding file download and this was the solution suggested.
{% for task in tasks %}
<tr><td><strong> name {{task.name}}</strong></td>
<td><strong> date {{task.date_created}}</strong></td>
<td><strong> status {{task.status}}</strong></td>
<td><strong> id {{task.id}}</strong></td>
<td><strong> input file {{task.input_file_path}}<td>
<td><a href="{{task.output_file_path}}" download>output file</td></tr>
{% endfor %}
The solution suggested is <a href="{{task.output_file_path}}" download> However, when i check my django request. It shows up this in console. GET /adv_filters/check/download/download/download/download/download/download/download/download/download/download/download/download/download/download/download/download/download/download/download/download/input_files/input_files/input_files/input_files/input_files/task4 HTTP/1.1" 200 2524
For testing purposes. I have set the location of the output file to be the location of the input file.
My relevant views.py
document.input_file_path = 'input_files/' + document.name
document.output_file_path = 'input_files/' + document.name
Models.py
doc = models.FileField(upload_to='input_files')
Is there anymore information i would need.
I guess simply putting file link(i.e. which I am assuming {{task.output_file_path}} is) should work.
<td><a href="{{task.output_file_path}}"</a> Download output file</td>

How to do multiple files upload on webpage and save on disk in web.py?

I was following LPTHW ex51 by Zed shaw http://learnpythonthehardway.org/book/ex51.html, and was doing his study drills on web.py , i am a web.py beginner and was successful in uploading an image on Webpage form and then storing it in a local folder. The issue is each image I store , replaces the earlier one. Also I cant figure out how to upload multiple images on server and store them all.
Here is my class Upload in app.py:
class Upload(object):
def GET(self):
web.header("Content-Type","text/html; charset=utf-8")
return render.upload()
def POST(self):
x= web.input(myfile={})
filedir= "C:/Users/tejas/Documents/filesave"
if 'myfile' in x:
fout = open(filedir + '/' + 'myfile.jpg', 'wb') # creates the file where the uploaded file should be stored
fout.write(x.myfile.file.read()) # writes the uploaded file to the newly created file.
fout.close() # closes the file, upload complete
return "Success! Your image has been saved in the given folder."
raise web.seeother('/upload')
and my upload form- upload.html :
<html>
<head><title>
<div id="header" <h1 style="color:blue;">Upload image file</h1><div/>
</title></head>
<body background-color=light-blue,font-family=verdana,font-size=100%;>
<form method="POST" enctype="multipart/form-data" action="">
<input type="file" name="myfile"/>
<br/> <br/><br/>
<input type="submit"/>
</form>
</body>
</html>
I tried searching a lot for similar questions but all in PHP , and so I try something similar with the code but I could not get it working. Any suggestions to improve the code?
the reason your code is replacing the earlier on is because your hardcoding the path to save the image
fout = open(filedir + '/' + 'myfile.jpg', 'wb')
everytime you upload the file to be altered is the same this could be corrected by adding an new name each time your uploading new file or extracting the name from web input
fout = open(filedir + '/' + x.myfile.filename, 'wb');
according to python when opening for writing files with the same name will be erased
make sure each new file you upload has different name from the previous uploaded

Showing 'cancel' on login page to return user to where they were (using django.contrib.auth)

We are using the #login_required decorator so that users see a login page if they try to access a url for which they need to be authenticated.
We want to show a 'cancel' button on the login page, which should return the user to whichever page they were on when they tried to access the url (by clicking a link etc - we don't need to deal with them manually entering the url).
At the moment our login.html looks for a request parameter 'login_cancel_url' and if present uses that (otherwise the home page).
However, this means we have to manually pass this parameter (set to the url of the current page) whenever we show a link or button that leads to an 'authentication required' url.
Is there a more elegant way to do this?
Thanks, Martin
Well you can try get the referrer header from the request but as far as I am aware, it's browser dependent and is not very reliable so the way you are doing it is probably best. You could try make life easier by creating template tags to avoid having to rewrite the return URL manually.
You are easily able to get the current URL from django's request object on any page, so instead of setting it manually on the link, you could write a snippet of html:
link_to_login.html
<!-- You should probably get /login/ using the {% url ... %} template tag -->
<a href="/login/?login_cancel_url={{ request.path|urlencode }}">
Login Page</a>
and use the {% include "link_to_login.html"%} template tag.
Alternatively, If the text needs to be different depending on the link you can instead create an inclusion template tag:
templatetags/extra_auth_tags.py
#register.inclusion_tag('templates/extra_auth_tags/login_link.html')
def login_link(context, text=None):
return {
'text':text
}
templates/extra_auth_tags/login_link.html
<!-- You should probably get /login/ using the {% url ... %} template tag -->
<a href="/login/?login_cancel_url={{ request.path|urlencode }}">
{% if text %}
{{ text }}
{% else %}
Some Default Text
{% endif %}
</a>
and then call it in your templates as {% login_link text="Check you messages" %}. Be aware that keyword arguments for inclusion tags are only supported in the django dev version so you might need to write the template tag by hand.