Django Redirect after downloading a file - django

I want to redirect to another view after downloading a file, but when I finish the download nothing happens and it remains in the same page. The dwonloading works perfectly. Any idea??
Views.py:
#The function that downloads the file
def download_file(path, format, fileName):
path = path+"."+format
filename = os.path.basename(path)
mimetype, encoding = mimetypes.guess_type(filename)
if fileName==None: fileName = filename
else: fileName = fileName+"."+format
response = HttpResponse(mimetype=mimetype)
response['Content-Disposition'] = 'attachment; filename=%s' %fileName
response.write(file(path, "rb").read())
return response
def download_downloaded_track(request, downloadedTrack_id):
dt = get_object_or_404(DownloadedTrack, id=downloadedTrack_id)
if request.method=='POST':
form = DownloadDownloadedTrackForm(request.POST)
if form.is_valid():
...
return download_file(downloadedTrackRoute+dt.fileName,format, name)
return HttpResponseRedirect(reverse('profile_detail'))
form = DownloadDownloadedTrackForm(initial={'format':'gpx'})
return render(request,'principal/downloadedTrack.html',{'form':form,'zone':dt.zone,'downloadedTrack':dt, 'layer':'downloadDownloadedTrack'})

Related

How to correctly to download file with django requests

I am running a Django app where I can upload files. Now I want to download the files using requests. I was trying to create a view where the file is downloaded, so I can then make a call with requests. But it doesn't quite work
My model:
class FileCollection(models.Model):
name = models.CharField(max_length=120, null=True, blank=True)
store_file = models.FileField(storage=PrivateMediaStorage(), null=True, blank=True)
creation_date = models.DateTimeField(null=True, blank=True)
My views
def fileview(request, *args, **kwargs):
file = FileCollection.objects.first()
file_path = file.store_file
print(file_path)
FilePointer = open(file_path, "r")
response = HttpResponse(FilePointer, content_type='application/msexcel')
response['Content-Disposition'] = 'attachment; filename=NameOfFile'
return response
It tells me that TypeError: expected str, bytes or os.PathLike object, not FieldFile
If I pass in the url provided in the apiview/admin I get: FileNotFoundError: [Errno 2] No such file or directory
Also tried:
def fileview(request):
path = FileCollection.objects.first()
obj = path.store_file
o = str(obj)
file_path = os.path.join(settings.MEDIA_ROOT, o)
print(file_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
but this gives me ValueError: The view file_storage_api.api.v1.views.fileview didn't return an HttpResponse object. It returned None instead.
Is that the right way to go?
I'm very grateful for help or hints.
Thanks so much
file_path = file.store_file
is not a file path but an instance of a FileField
try using
file_path = file.store_file.name
and use the second snippet
EDIT: here is the code I use:
l_targetFile is the path to the actual file
l_prjPath = os.path.realpath(os.path.dirname(__file__)).replace(<adapt the path here>)
l_userFileName= <file field>.name.replace('<upload to sub-dir>','')
l_targetFile = l_prjPath + '/media/' + l_fileObj.file_obj.name
#return the file
response = FileResponse(open(l_targetFile, 'rb'),\
(l_responseDisposition == 'attachment'))
#process the filename as stored on the local machine in case of download
try:
#check if it will throw
l_tmpUserName = l_userFileName.encode('ascii')
#no error use the non-encoded filename
l_fileExpr = 'filename="{0}"'.format(l_userFileName)
except UnicodeEncodeError:
# Handle a non-ASCII filename
l_fileExpr = "filename*=utf-8''{}".format(quote(l_userFileName))
response['Content-Disposition'] = '{0};{1};'.format(l_responseDisposition,l_fileExpr)
if '.pdf' in l_userFileName:
response['Content-Type'] = 'application/pdf'
elif l_dataSource == CMSArchiveEntry.SOURCE_TAG:
response['Content-Type'] = 'text/html; charset=utf-8'
return response

attach mail in django format error: not a pdf or damaged

for my homework, I'm trying to send an attach pdf to e-mail.I have generated pdf that I want to send.
but, when I download the pdf file I have format error: not a pdf or damaged at the opening of the file.
definition of render_to_pdf
utils.py
from io import BytesIO
from django.http import HttpResponse
from django.template.loader import get_template
from xhtml2pdf import pisa
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return None
pdf generator function
class GeneratePDF(View):
context_object_name = 'services'
template_name = 'pdf.html'
def get(self, request, *args, **kwargs):
template = get_template('configuration/pdf.html')
f=Reservation.objects.all().filter(Q(valide=True, option__in=Option.objects.all().filter(Q(code_option='GTR',
posseder_niveau__in=Posseder_Niveau.objects.all().filter(niveau_id = 1))))).order_by('date_du_jour_reserve')
c = Plage_Horaire.objects.all()
context = {
"c":c,
'f':f,
}
html= template.render(context)
pdf = render_to_pdf('configuration/pdf.html', context)
if pdf:
response = HttpResponse(pdf, content_type='application/pdf')
filename = "emploidetemps.pdf"
content = "inline; filename=%s " %filename
download = request.GET.get("download")
if download:
content = "attachment; filename=%s" %(filename)
response['Content-Disposition'] = content
return response
return HttpResponse("Not found")
mail function
def mailjoin(request):
GeneratePDF.as_view()
email = EmailMessage()
email.subject = "test"
email.body='emploi de temps'
email.from_email = settings.EMAIL_HOST_USER
email.to = ['xxxxxxxx#gmail.com' ]
email.attach("emploidetemps.pdf", 'application/pdf')
email.send()
First - GeneratePDF.as_view() returns a callable view, not pdf file do call like -
file = GeneratePDF.as_view()(request)
Second your GeneratePDF returns HttpResponse, you have to save the pdf and then add with full path or just don't use this.
If you do not save then do something like -
def mailjoin(request):
template = get_template('configuration/pdf.html')
f=Reservation.objects.all().filter(Q(valide=True, option__in=Option.objects.all().filter(Q(code_option='GTR',
posseder_niveau__in=Posseder_Niveau.objects.all().filter(niveau_id = 1))))).order_by('date_du_jour_reserve')
c = Plage_Horaire.objects.all()
context = {
"c":c,
'f':f,
}
html= template.render(context)
pdf = render_to_pdf('configuration/pdf.html', context)
email = EmailMessage()
email.subject = "test"
email.body='emploi de temps'
email.from_email = settings.EMAIL_HOST_USER
email.to = ['xxxxxxxx#gmail.com' ]
email.attach('emploidetemps.pdf', pdf, 'application/pdf')
email.send()

Django Rest Framework function view post not working

So I am trying to serve a static file through a simple Django Rest framework function view. It gives me 200 code but doesn't download the file.
Here is the code :
#api_view(['POST'])
def download_file(request):
if request.method == 'POST':
serializer = MySerializer(data=request.data)
filename = 'file.xlsx'
file_full_path = "src/{0}".format(filename)
with open(file_full_path, 'rb') as f:
file = f.read()
response = HttpResponse(file, content_type="application/xls")
response['Content-Disposition'] = "attachment; filename={0}".format(filename)
response['Content-Length'] = os.path.getsize(file_full_path)
return response
return Response(status=status.HTTP_400_BAD_REQUEST)
What am I doing wrong here?
You are trying to download file with a HTTP POST method, I don't think it's a nice way. So try HTTP GET for downloading. If you wish to provide extra arguments (payload in POST method), you could do it using Query Parameter as /api/end/point/?param=value1&param2=value2.
So, try the following snippet,
#api_view(['GET'])
def download_file(request):
if request.method == 'GET':
filename = 'file.xlsx'
file_full_path = "src/{0}".format(filename)
with open(file_full_path, 'rb') as f:
file = f.read()
response = HttpResponse(file, content_type="application/xls")
response['Content-Disposition'] = "attachment; filename={0}".format(filename)
response['Content-Length'] = os.path.getsize(file_full_path)
return response
return Response(status=status.HTTP_400_BAD_REQUEST)

Django : How to upload csv file in unit test case using APIClient

I would like to write a unit test for a view on a Django REST Framework application. The test should upload a CSV file using the POST.
#staticmethod
def _file_upload(client, string, args, file_name):
base_path = os.path.dirname(os.path.realpath(__file__))
with open(base_path + file_name, 'rb') as data:
data = {
'file': data
}
response = client.post(reverse(string, args=[args]), data, format = "multipart")
return response.status_code, response.data
The above code I used which obviously doesn't work it shows the following error
Missing filename. Request should include a Content-Disposition header with a filename parameter.
The following code is the one that I want to test via unit testing.
class ChartOfAccounts(views.APIView):
parser_classes = (JSONParser, FileUploadParser)
def post(self, request, pk, *args, **kwargs):
request.FILES['file'].seek(0)
csv_data = CSVUtils.format_request_csv(request.FILES['file'])
try:
coa_data = CSVUtils.process_chart_of_accounts_csv(company, csv_data)
serializer = CoASerializer(coa_data, many=True)
if len(serializer.data) > 0:
return Utils.dispatch_success(request, serializer.data)
except Exception as e:
error = ["%s" % e]
return Utils.dispatch_failure(request, 'DATA_PARSING_ISSUE', error)
Any help regarding this is welcome. Thanks in advance
I have fixed my issue using the different approach with HTTP headers HTTP_CONTENT_DISPOSITION, HTTP_CONTENT_TYPE by this reference
And here is my code
#staticmethod
def _file_upload_csv( string, args, file_name):
base_path = os.path.dirname(os.path.realpath(__file__))
data = open(base_path + file_name, 'rb')
data = SimpleUploadedFile(content = data.read(),name = data.name,content_type='multipart/form-data')
factory = RequestFactory()
user = User.objects.get(username=UserConstant.ADMIN_USERNAME)
view = ChartOfAccounts.as_view()
content_type = 'multipart/form-data'
headers= {
'HTTP_CONTENT_TYPE': content_type,
'HTTP_CONTENT_DISPOSITION': 'attachment; filename='+file_name}
request = factory.post(reverse(string, args=[args]),{'file': data},
**headers)
force_authenticate(request, user=user)
response = view(request, args)
return response.status_code, response.data
**headers done the trick...
Here's what i did
#patch("pandas.read_csv")
#patch("pandas.DataFrame.to_sql")
def test_upload_csv_success(self, mock_read_csv, mock_to_sql) -> None:
"""Test uploading a csv file"""
file_name = "test.csv"
# Open file in write mode (Arrange)
with open(file_name, "w") as file:
writer = csv.writer(file)
# Add some rows in csv file
writer.writerow(["name", "area", "country_code2", "country_code3"])
writer.writerow(
["Albania", 28748, "AL", "ALB"],
)
writer.writerow(
["Algeria", 2381741, "DZ", "DZA"],
)
writer.writerow(
["Andorra", 468, "AD", "AND"],
)
# open file in read mode
data = open(file_name, "rb")
# Create a simple uploaded file
data = SimpleUploadedFile(
content=data.read(), name=data.name, content_type="multipart/form-data"
)
# Perform put request (Act)
res = self.client.put(CSV_URL, {"file_name": data}, format="multipart")
# Mock read_csv() and to_sql() functions provided by pandas module
mock_read_csv.return_value = True
mock_to_sql.return_value = True
# Assert
self.assertEqual(res.status_code, status.HTTP_201_CREATED)
self.assertEqual(res.data, "Data set uploaded")
# Delete the test csv file
os.remove(file_name)

django download file from server to user's machine,or read online

I am uploading some .doc and .txt documents on my server, and i'd like to have two options:
-the user to be able to download the document
-the user to be able to read it online
i've read some code for the download function, but it doesn't seem to work.
my code:
def download_course(request, id):
course = Courses.objects.get(pk = id)
response = HttpResponse(mimetype='application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['X-Sendfile'] = smart_str(/root/)
return response
def save_course(request, classname):
classroom = Classroom.objects.get(classname = classname)
if request.method == 'POST':
form = CoursesForm(request.POST, request.FILES)
if form.is_valid():
handle_uploaded_file(request.FILES['course'])
new_obj = form.save(commit=False)
new_obj.creator = request.user
new_obj.classroom = classroom
new_obj.save()
return HttpResponseRedirect('.')
else:
form = CoursesForm()
return render_to_response('courses/new_course.html', {
'form': form,
},
context_instance=RequestContext(request))
def handle_uploaded_file(f):
destination = open('root', 'wb+')
for chunk in f.chunks():
destination.write(chunk)
destination.close()
any clue?
thanks!
You can open a File object to read the actual file, and then start download the file like this code:
path_to_file = os.path.realpath("random.xls")
f = open(path_to_file, 'r')
myfile = File(f)
response = HttpResponse(myfile, content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=' + name
return response
path_to_file: is where the file is located on the server.
f = open(path_to_file, 'r') .. to read the file
the rest is to download the file.
Should the response['X-Sendfile'] be pointing to the file? It looks like it's only pointing at '/root/', which I'm guessing is just a directory. Maybe it should look more like this:
def download_course(request, id):
course = Courses.objects.get(pk = id)
path_to_file = get_path_to_course_download(course)
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
Where get_path_to_course_download returns the location of the download in the file system (ex: /path/to/where/handle_uploaded_files/saves/files/the_file.doc)