I'm quite new to using Django and I am trying to develop a website where the user is able to upload a number of excel files, these files are then stored in a media folder Webproject/project/media.
def upload(request):
if request.POST:
form = FileForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return render_to_response('project/upload_successful.html')
else:
form = FileForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('project/create.html', args)
The document is then displayed in a list along with any other document they have uploaded, which you can click into and it will displays basic info about them and the name of the excelfile they have uploaded. From here I want to be able to download the same excel file again using the link:
Download Document
My urls are
urlpatterns = [
url(r'^$', ListView.as_view(queryset=Post.objects.all().order_by("-date")[:25],
template_name="project/project.html")),
url(r'^(?P<pk>\d+)$', DetailView.as_view(model=Post, template_name="project/post.html")),
url(r'^upload/$', upload),
url(r'^download/(?P<path>.*)$', serve, {'document root': settings.MEDIA_ROOT}),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
but I get the error, serve() got an unexpected keyword argument 'document root'. can anyone explain how to fix this?
OR
Explain how I can get the uploaded files to to be selected and served using
def download(request):
file_name = #get the filename of desired excel file
path_to_file = #get the path of desired excel file
response = HttpResponse(mimetype='application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['X-Sendfile'] = smart_str(path_to_file)
return response
You missed underscore in argument document_root. But it's bad idea to use serve in production. Use something like this instead:
import os
from django.conf import settings
from django.http import HttpResponse, Http404
def download(request, path):
file_path = os.path.join(settings.MEDIA_ROOT, path)
if os.path.exists(file_path):
with open(file_path, 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/vnd.ms-excel")
response['Content-Disposition'] = 'inline; filename=' + os.path.basename(file_path)
return response
raise Http404
You can add "download" attribute inside your tag to download files.
<a href="/project/download" download> Download Document </a>
https://www.w3schools.com/tags/att_a_download.asp
Reference:
In view.py Implement function like,
def download(request, id):
obj = your_model_name.objects.get(id=id)
filename = obj.model_attribute_name.path
response = FileResponse(open(filename, 'rb'))
return response
When you upload a file using FileField, the file will have a URL that you can use to point to the file and use HTML download attribute to download that file you can simply do this.
models.py
The model.py looks like this
class CsvFile(models.Model):
csv_file = models.FileField(upload_to='documents')
views.py
#csv upload
class CsvUploadView(generic.CreateView):
model = CsvFile
fields = ['csv_file']
template_name = 'upload.html'
#csv download
class CsvDownloadView(generic.ListView):
model = CsvFile
fields = ['csv_file']
template_name = 'download.html'
Then in your templates.
#Upload template
upload.html
<div class="container">
<form action="#" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<button class="btn btn-primary btn-sm" type="submit">Upload</button>
</form>
#download template
download.html
{% for document in object_list %}
Download
{% endfor %}
I did not use forms, just rendered model but either way, FileField is there and it will work the same.
I've found Django's FileField to be really helpful for letting users upload and download files. The Django documentation has a section on managing files. You can store some information about the file in a table, along with a FileField that points to the file itself. Then you can list the available files by searching the table.
#Biswadp's solution worked greatly for me
In your static folder, make sure to have the desired files you would like the user to download
In your HTML template, your code should look like this :
Download
Using the below approach makes everything less secure since any user can access any user's file.
<a href="/project/download" download> Download Document </a>
Using the below approach makes no sense since Django only handles one requests at the time (unless you are using gunicorn or something else), and believe me, the below approach takes a lot of time to complete.
def download(request, path):
file_path = os.path.join(settings.MEDIA_ROOT, path)
if os.path.exists(file_path):
with open(file_path, 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/vnd.ms-excel")
response['Content-Disposition'] = 'inline; filename=' + os.path.basename(file_path)
return response
raise Http404
So what is the optimum solution?
Use Nginx authenticated routes. When requesting a file from Nginx you can make a request to a route and depending on the HTTP response Nginx allows to denies that request. This makes it very secure and also scalable and performant.
You can ready about more here
import mimetypes
from django.http import HttpResponse, Http404
mime_type, _ = mimetypes.guess_type(json_file_path)
if os.path.exists(json_file_path):
with open(json_file_path, 'r') as fh:
response = HttpResponse(fh, content_type=mime_type)
response['Content-Disposition'] = "attachment; filename=%s" % 'config.json'
return response
raise Http404
<a href='/your-download-view/' download>Download</a>
In your view:
from django.http import FileResponse
def download(request):
# pre-processing, authorizations, etc.
# ...
return FileResponse(open(path_to_file, 'rb'), as_attachment=True)
Simple using html like this downloads the file mentioned using static keyword
Download CV
1.settings.py:
MEDIA_DIR = os.path.join(BASE_DIR,'media')
#Media
MEDIA_ROOT = MEDIA_DIR
MEDIA_URL = '/media/'
2.urls.py:
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
3.in template:
<a href="{{ file.url }}" download>Download File.</a>
Work and test in django >=3
for more detail use this link:
https://youtu.be/MpDZ34mEJ5Y
If the file is a FileField in the model, this is the way I do it:
try:
download_file = PrintingFile.objects.get(pk=kwargs.get('pk_file', 0))
return FileResponse(download_file.file.open(), as_attachment=True)
except PrintingFile.DoesNotExist:
raise Http404
More here
I use this method:
{% if quote.myfile %}
<div class="">
<a role="button"
href="{{ quote.myfile.url }}"
download="{{ quote.myfile.url }}"
class="btn btn-light text-dark ml-0">
Download attachment
</a>
</div>
{% endif %}
If you hafe upload your file in media than:
media
example-input-file.txt
views.py
def download_csv(request):
file_path = os.path.join(settings.MEDIA_ROOT, 'example-input-file.txt')
if os.path.exists(file_path):
with open(file_path, 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/vnd.ms-excel")
response['Content-Disposition'] = 'inline; filename=' + os.path.basename(file_path)
return response
urls.py
path('download_csv/', views.download_csv, name='download_csv'),
download.html
a href="{% url 'download_csv' %}" download=""
Related
i have an app in django that do some processes and build a file, in one section, i want to show the user that file to download that.
(for example, user enter a name in front-end and the app give him a pdf file to download).
the file building process is ok and it is in /app_dir/media/app/report/username/file.pdf
here is my code, but it does not worked and i faced some problems.
can you please help me, where is my problem?
and how i can make that user-specefic? each user just can access to his files.
views.py (my_main_function):
#login_required(login_url='/login/')
def my_function(request):
if request.method == 'GET':
return render(request, 'app/my_function.html')
else:
try:
#my main process to build .PDF file
except ValueError:
return render(request, 'app/dashboard.html', {'error':'Bad data passed in. Try again.'})
return render(request, 'app/download.html')
views.py (download function):
def download_file(request):
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
filename = f"{file}.pdf"
# Define the full file path
filepath = f"{BASE_DIR}/app/media/app/reports/{user_name}/{filename}"
# Open the file for reading content
path = open(filepath, 'rb')
path.read()
# Set the return value of the HttpResponse
response = HttpResponse(path, content_type='application/pdf')
# Set the HTTP header for sending to browser
response['Content-Disposition'] = "attachment; filename=%s" % filepath
# Return the response value
return response
urls.py:
path('download/', views.download_file, name='download_file'),
simple testing download.html file:
<html>
<title>Download File</title>
</head>
<body>
<enter>
<h1>Download File using link</h1>
Download PDF
</center>
</body>
</html>
It is not clear what problems you have encountered, but there are some lines I would correct in your code
# first of all why not use django.http.FileResponse instead of HttpResponse?
# https://docs.djangoproject.com/en/3.2/ref/request-response/#fileresponse-objects
from django.http import FileResponse
# if you want files to be accessible only to owners
# you probably should force user to login before download
#login_required
def download_file(request):
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
filename = f"{file}.pdf"
filepath = f"{BASE_DIR}/app/media/app/reports/{user_name}/{filename}"
# somewhere here you need to check if user has access to the file
# if files ownership based solely on {user_name} dir in filesystem
# then it is enough to check if file exists
if os.path.exists(filepath):
response = FileResponse(open(filepath, 'rb'))
# it is probably better to use filename instead of filepath
response['Content-Disposition'] = "attachment; filename=%s" % filename
return response
else:
raise Http404
I am trying to download a CSV file from the server to a client machine via a jQuery Ajax call, but for some reason the return response is not triggering the download. I know that there are several other questions which are quite similar, however, none of them are specifically using ajax with Django (that I've found), so I'm not sure if something needs to be done differently. The closest thing I could find was this one: download file using an ajax request which sets the window.location to a download.php file on success, but that doesn't really seem applicable. Everything I've been able to find, including the django documentation, uses some method that is very similar to what I have and yet every variation I've tried produces more or less the same result - nothing gets downloaded.
I've confirmed that each step of the process is executing correctly except for the last one in the views.py.
download_page.html:
{% extends 'base.html' %}
{% load staticfiles %}
<script>
$(function() {
$('#download').on('click', function () {
var pk = $(this).val();
$.ajax({
url: '/ajax/download/',
data: {'pk': pk}
});
});
});
</script>
{% block body %}
...
<button id="download" value="{{ view_id }}">Download</button>
...
{% endblock %}
urls.py:
urlpatterns = [
...
url(r'^ajax/download/', views.download, name='download'),
...
]
views.py:
import pathlib2
from django.http import HttpResponse
from src.apps.main.models import DataModel
def download(request):
pk = request.GET.get('pk', None)
fname, fpath = DataModel.export_to_csv(pk) # does the export and returns fullpath to file
if pathlib2.Path(fpath).exists():
file_download = open(fpath, 'r')
response = HttpResponse(file_download, content_type='application/csv')
response['Content-Disposition'] = 'attachment; filename="{}"'.format(fname)
return response
It gets all the way to the point at which it should return the response and then nothing happens. There are no warnings or errors, it just seems to silently finish without ever triggering the download on the client side. I'm guessing that there's something I need to do differently to return the file, but I've not been able to determine what that is.
maybe could do fname of you are a path
response['Content-Disposition'] = 'attachment; filename="{}"'.format(fname)
you can try:
response['Content-Type'] = 'application/force-download'
response['Content-Disposition'] = 'attachment; filename="donwload.scv"'
note: you can edit the filename accordingly.
I need to upload profile images into diferent folders in Django. So, I have a folder for each account, and the profile image have to go to the specific folder. How can I do that?
Here is my uploadprofile.html
<form action="{% url 'uploadimage' %}" enctype="multipart/form-data" method="POST">
{% csrf_token %}
<input type="file" name="avatar" accept="image/gif, image/jpeg, image/png">
<button type="submit">Upload</button>
</form>
And here is my view in views.py
def uploadimage(request):
img = request.FILES['avatar'] #Here I get the file name, THIS WORKS
#Here is where I create the folder to the specified profile using the user id, THIS WORKS TOO
if not os.path.exists('static/profile/' + str(request.session['user_id'])):
os.mkdir('static/profile/' + str(request.session['user_id']))
#Here is where I create the name of the path to save as a VARCHAR field, THIS WORKS TOO
avatar = "../../static/profile/" + str(request.session['user_id']) + "/" + str(img)
#THEN I HAVE TO COPY THE FILE IN img TO THE CREATED FOLDER
return redirect(request, 'myapp/upload.html')
You can pass a callable to upload_to. Basically, what it means is whatever value that callable returns, the image will be uploaded in that path.
Example:
def get_upload_path(instance, filename):
return "%s/%s" % (instance.user.id, filename)
class MyModel:
user = ...
image = models.FileField(upload_to=get_upload_path)
There's more information in the docs and an example too, though similar to what I posted above.
By looking at Django docs what you get when you do img = request.FILES['avatar'] you get a file descriptor that points to an open file with your image.
Then you should to dump the contents in your actual avatar path, right?
#Here is where I create the name of the path to save as a VARCHAR field, THIS WORKS TOO
avatar = "../../static/profile/" + str(request.session['user_id']) + "/" + str(img)
# # # # #
with open(avatar, 'wb') as actual_file:
actual_file.write(img.read())
# # # # #
return redirect(request, 'myapp/upload.html')
Beware: the code is untested.
from django.shortcuts import render
from django.conf import settings
from django.core.files.storage import FileSystemStorage
def uploadimage(request):
if request.method == 'POST' and request.FILES['avatar']:
img = request.FILES['avatar']
fs = FileSystemStorage()
#To copy image to the base folder
#filename = fs.save(img.name, img)
#To save in a specified folder
filename = fs.save('static/profile/'+img.name, img)
uploaded_file_url = fs.url(filename) #To get the file`s url
return render(request, 'myapp/upload.html', {
'uploaded_file_url': uploaded_file_url
})
return render(request, 'myapp/upload.html')
I need to store a file path in db using django via ajax form submission .
Here is my view:
def dashboard(request):
container=[]
DIR = os.path.realpath("/home/user/Desktop/Demo")
WAY = os.listdir(DIR)
for file in WAY:
if file.endswith('.mp4'):
file_name = file
FDIR=os.path.join(DIR, file)
container.append(FDIR)
return render(request, 'dashboard.html', {'container': container})
def new_scheduler(request):
if request.method =='POST':
f_name = request.POST.get('file')
dateAndTime = request.POST.get('dateAndTime')
Scheduled_data = schedulesdb.objects.create(
f_name = file,
dateAndTime = dateAndTime,
)
Scheduled_data.save()
return HttpResponse ('done')
It save in database like <type 'file'> .
Here is my model.py:
class schedulesdb(models.Model):
f_name = models.CharField(max_length=100)
dateAndTime = models.DateTimeField(['%Y-%m-%d %H:%M:%S'],null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=2)
def __unicode__(self): # on Python 2
return self.f_name
Thanks in advance :)
From your code it's not 100% clear whether you're intending to handle file uploads from the client, or simply store strings that happen to be a file path (potentially for locating a file on some remote filesystem).
1. File uploads
Consider using the FileField model field type rather than the CharField.
The Django documentation has a solid explanation and examples of how to do simple file uploads.
2. Obtaining the actual POST data value for the f_name field
Your code sample is storing "", because you're assigning 'file' (which is a builtin type) rather than the f_name variable that you previously declared. Like this:
def new_scheduler(request):
if request.method =='POST':
f_name = request.POST.get('file')
dateAndTime = request.POST.get('dateAndTime')
Scheduled_data = schedulesdb.objects.create(
f_name = f_name, # Note the use of f_name instead of file
dateAndTime = dateAndTime,
)
Scheduled_data.save()
return HttpResponse ('done')
I haven't even used ajax, but I stored file path in mysql and stored file in media folder in django
Here's my views.py:
from CRUDoperation.models import EmpModel
def upload(request):
if request.method == 'POST':
saverecord=EmpModel()
myfile = request.FILES['myfile']
fs = FileSystemStorage()
filename = fs.save(myfile.name, myfile)
uploaded_file_url = fs.url(filename)
saverecord.file=uploaded_file_url
return render(request,'upload.html')
models.py file
class EmpModel(models.Model):
file=models.CharField(max_length=150)
class Meta:
db_table="employee"
settings.py file
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
my html code:
{% load static %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="myfile">
<button type="submit">Upload</button>
</form>
I'm new to Google app engine with python ,please help me!
Here is my html code:
<form action="" method="POST">
<div class="form-group">
<label for="uploaded_file">Attached file:</label>
<input type="file" id="uploaded_file" name="uploaded_file">
</div>
<div class="form-group">
<button class="btn-primary" type="submit">Save note</button>
</div>
</form>
Here is my python code:
def post(self):
uploaded_file = self.request.POST.get('uploaded_file')
file_name = getattr(uploaded_file, 'filename', None)
file_content = getattr(uploaded_file, 'file', None)
if uploaded_file:
self.response.out.write(uploaded_file)
self.response.out.write(file_name)
self.response.out.write(file_content)
I deploy my project to Google app engine and visit the website. I choose a picture and click the submit button, it can show uploaded_file(file's name). But, file_name and file_content show None.
If I modify my code :
def post(self):
uploaded_file = self.request.POST.get('uploaded_file')
file_name = getattr(uploaded_file, 'filename')
file_content = getattr(uploaded_file, 'file')
It will show:
File "C:\Users\pc2\Desktop\test\main.py", line 98, in post
file_name = getattr(uploaded_file, 'filename')
AttributeError: 'unicode' object has no attribute 'filename'
Someone help me to get file or picture ,please!
In your form, you need to an 'enctype' attribute so that uploaded files are handled properly - see this answer for more details on enctype. Your form tag should look like this:
<form action="" method="POST" enctype="multipart/form-data">
Change your post method to this:
def post(self):
uploaded_file = self.request.POST.get('uploaded_file')
file_name = getattr(uploaded_file, 'filename', None)
file_content = getattr(uploaded_file, 'file', None)
if uploaded_file is not None:
self.response.out.write(uploaded_file)
self.response.out.write(file_name)
self.response.out.write(file_content)
The change here is changing if uploaded_file: to if uploaded_file is not None:. This is because a successfully uploaded file will not be None, but would still fail your original if test. I would leave the 'None' arguments to getattr in place - these will prevent exceptions if the user clicks on submit but has not uploaded a file.
Finally, uploaded files do not have a file_content attribute, so this will always be None. If you want to access the file's raw bytes you will need to do
file_content = uploaded_file.file.read()
Note that the file content could be very large, and will not render as an image if you just write it out to the response - you'll just see the raw bytes.