How to send a PDF file by DRF - python

I have a request for you, can you please help me with one question.
How can I send a pdf file via api.
It starts like this, they send me the base64 format and I accept it and do the decoding.
Then I need to send this file to another endpoint, but I just can’t put it there. Could you please help me
According to Postman, my file sits quietly and works as it should. The picture shows that it takes the form-date.
def sendDocs(photoBack):
try:
headers = {'Content-Type':'multipart/form-data;',
'bsauth': 'key'}
import base64
decodedData = base64.b64decode((photoBack))
pdfFile = open('photoBack.pdf', 'rb+')
pdfFile.write(decodedData)
pdfFile.close()
response = HttpResponse(pdfFile, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="photoBack.pdf"'
url = f'https://file.shinhanfinance.kz/files/shinhanfinance/add?client={1013246509}'
files = {"file":response}
firstPost1 = requests.post(url,data =response,headers=headers)
print(Response(firstPost1))
return Response({firstPost1})
except:
return Response({'bruh what wrong ?'})
Here my code

def sendDocs(photoBack):
try:
headers = {'Content-Type':'multipart/form-data;',
'bsauth': 'key'}
import base64
decodedData = base64.b64decode((photoBack))
pdfFile = open('photoBack.pdf', 'rb+')
pdfFile.write(decodedData)
pdfFile.close()
response = HttpResponse(pdfFile, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="photoBack.pdf"'
url = f'https://file.shinhanfinance.kz/files/shinhanfinance/add?client={1013246509}'
files = {"file":response}
firstPost1 = requests.post(url,data =response,headers=headers)
print(Response(firstPost1))
return Response({firstPost1})
except:
return Response({'bruh what wrong ?'})

You can try to use decodedData, and put it into file parameters.
firstPost1 = requests.post(url, files={"file": decodedData}, headers=headers)
I think here is your solution How to upload file with python requests?

Related

Serving .json file to download

I am trying to serve a .json file through this function. The problem is that every time I make the request the browser displays the content instead of downloading the file.
I think it could be due to the fact that I am using .read() as a parameter for the HttpResponse object constructor. However, if I use only the file object, I get the following exception:
TypeError: cannot serialize '_io.BufferedRandom' object
Code
try:
invoices = models.Invoice.objects.filter(pk__in=document_ids).order_by(*ordering)
pcustomers = models.CustomerProxy.objects.all()
mixed_query = list(invoices) + list(pcustomers)
file = tempfile.NamedTemporaryFile(suffix='.json')
file.write(serializers.serialize('json', mixed_query).encode())
file.seek(0)
response = HttpResponse(file.read(), content_type='application/json')
response['Content-Disposition'] = 'attachment; filename=%s' % file.name
response['Content-Length'] = os.path.getsize(file.name)
except Exception:
raise
return response
You don't need to go through the whole file generation process to create a downloadable file, you just need to add the Content-Disposition header normally. Does the code below work?
...
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'
Based on the code that you show, you do not need to write to a temporary file. Why don't you just pass the result of serialize() into HttpResponse()?
response = HttpResponse(serializers.serialize('json', mixed_query), content_type='application/json')
You can set the attachment name to whatever you like, something descriptive would seem to be better than the random alphanumeric string generated by tempfile.NamedTemporaryFile().
response['Content-Disposition'] = 'attachment; filename="invoices_and_customers.json"'
If you really want to specify the length:
response['Content-Length'] = len(response.content)
or you could add the ConditionalGetMiddleware middleware to your settings and have Django add the Content-Length for you.
add this to your Http response
HttpResponse(mimetype='application/force-download')

How to POST a tgz file in Python using urllib2

I would like to POST a .tgz file with the Python urllib2 library to a backend server. I can't use requests due to some licensing issues. There are some examples of file upload on stackoverflow but all relate to attaching a file in a form.
My code is the following but it unfortunately fails:
stats["random"] = "data"
statsFile = "mydata.json"
headersFile = "header-data.txt"
tarFile = "body.tgz"
headers = {}
#Some custom headers
headers["X-confidential"] = "Confidential"
headers["X-version"] = "2"
headers["Content-Type"] = "application/x-gtar"
#Create the json and txt files
with open(statsFile, 'w') as a, open(headersFile, 'w') as b:
json.dump(stats, a, indent=4)
for k,v in headers.items():
b.write(k+":"+v+"\n")
#Create a compressed file to send
tar = tarfile.open(tarFile, 'w:gz' )
for name in [statsFile,headersFile]:
tar.add(name)
tar.close()
#Read the binary data from the file
with open(tarFile, 'rb') as f:
content = f.read()
url = "http://www.myurl.com"
req = urllib2.Request(url, data=content, headers=headers)
response = urllib2.urlopen(req, timeout=timeout)
If I use requests, it works like a charm:
r = requests.post(url, files={tarFile: open(tarFile, 'rb')}, headers=headers)
I essentially need the equivalent of the above for urllib2. Does anybody maybe know it? I have checked the docs as well but I was not able to make it work..What am I missing?
Thanks!

HttpResponse content type for csv and other extentions doesn't work in firefox but works in Chrome and IE

I am using PYTHON+DJANGO to implement a file sharing system. When a user attempts to download a file it works well in Chrome and IE but not Firefox, Firefox returns part of the file name and no extension if it does not recognize the extension (e.g. .pl and .csv)
View
filename = os.path.join(MEDIA_ROOT, entry.myfile.url)
wrapper = FileWrapper(file(filename,'rb'))
response = HttpResponse(wrapper, content_type='application/octet-stream')
response['Content-Length'] = os.path.getsize(filename)
response['Content-Disposition'] = "attachment; filename=" + entry.name
I tried content_type=mimetypes.guess_type(filename) but this didn't solve the problem
I also tried replacing any spaces within the filename with periods, that did work! But I'm a sure there is a clean solution!!
Answer to an old question, I know, but the actual issue is that you didn't enclose the filename with double quotes (and it has to be double, not single). IE and Chrome will read until the end of the line, but Firefox will read until the first space and stop.
So just change response['Content-Disposition'] = "attachment; filename=" + entry.name to response['Content-Disposition'] = 'attachment; filename="%s"'%(entry.name) and you're set.
Based on django.views.static:
import mimetypes
import os
import stat
from django.http import HttpResponse
statobj = os.stat(fullpath)
mimetype, encoding = mimetypes.guess_type(fullpath)
mimetype = mimetype or 'application/octet-stream'
with open(fullpath, 'rb') as f:
response = HttpResponse(f.read(), mimetype=mimetype)
if stat.S_ISREG(statobj.st_mode):
response["Content-Length"] = statobj.st_size
if encoding:
response["Content-Encoding"] = encoding
response['Content-Disposition'] = 'inline; filename=%s'%os.path.basename(fullpath)
return response

How to download a file uploaded using django-filebrowser?

I am trying to create a download of a file object. the file was added using django-filebrowser which means it is turn in to a string path to the the file. I have tried the following:
f = Obj.objects.get(id=obj_id)
myfile = FileObject(os.path.join(MEDIA_ROOT, f.Audio.path))
...
response = HttpResponse(myfile, content_type="audio/mpeg")
response['Content-Disposition'] = 'attachment; filename=myfile.mp3'
return response
The file that is downloaded contains the string of the path to the file location and not the file. Could anyone be of assistance on how to access the file object?
f = Obj.objects.get(id=obj_id)
myfile = open(os.path.join(MEDIA_ROOT, f.Audio.path)).read()
...
response = HttpResponse(myfile, content_type="audio/mpeg")
response['Content-Disposition'] = 'attachment; filename=myfile.mp3'
return response
NOTE! This is not memory friendly! Since the whole file is put into memory. You're better of using a webserver for file serving or if you want to use Django for file serving you could use xsendfile or have a look at this thread
You need to open the file and send it's binary contents back in the response. So something like:
fileObject = FileObject(os.path.join(MEDIA_ROOT, f.Audio.path))
myfile = open(fileObject.path)
response = HttpResponse(myfile.read(), mimetype="audio/mpeg")
response['Content-Disposition'] = 'attachment; filename=myfile.mp3'
return response
Hope that gets what you're looking for.

How to save file data from POST variable and load it back to response in Python Django?

I have a such problem - I am using Python 2.6 / Django 1.3 and I need to accept as POST variable with key 'f', which contains a binary data. After that, I need to save data in a file.
POST
T$topX$objectsX$versionY$archiverО©ҐR$0О©ҐО©ҐО©Ґull_=<---------------------- content of file -------------------->О©ҐО©Ґ_NSKeyedArchive(258:=CО©ҐО©Ґ
Code
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
def save(request):
upload_file = request.POST['f']
save_path = default_storage.save('%s%s' % (save_dir, filename),
ContentFile(upload_file))
When I am trying to do
nano /tmp/myfile.zip
It returns data like
T^#^#^#$^#^#^#t^#^#^#o^#^#^#p^#^#^#X^#^#^#$^#^#^#o^#^#^#b^#^#^#j^#^#^#e^#^#^#c^#^#^#t^#^#^#s^#^#^#X^#^#^#$^#^#^#v^#^#^#e^#^#^#r^#^#^#s^#^#^#i^#^#$
When its done, I am going to read saved file
def read(request):
user_file = default_storage.open(file_path).read()
file_name = get_filename(file_path)
response = HttpResponse(user_file, content_type = 'text/plain',
mimetype = 'application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % file_name
response['Content-Length'] = default_storage.size(file_path)
return response
In case, when I am writing
print user_file
It returns a correct data, but when I am returning a HttpResponse it has a different data from a source
It would probably be easier, and more memory efficient if you just save the data into a file, and like #keckse said, let a browser stream it. Django is very inefficient in streaming data. It will all depend on the size of the data. If you want to stream it with django anyways, it can be done like this:
from django.http import HttpResponse
import os.path
import mimetypes
def stream(request, document, type=None):
doc = Document.objects.get(pk=document)
fsock = open(doc.file.path,"r")
file_name = os.path.basename(doc.file.path)
mime_type_guess = mimetypes.guess_type(file_name)
if mime_type_guess is not None:
response = HttpResponse(fsock, mimetype=mime_type_guess[0])
response['Content-Disposition'] = 'attachment; filename=' + file_name
return response
In your case you might want to set the mime type manually, you can try out application/octet-stream too. The mainpassing iterators difference is that you pass the "string" from file.read(), instead of the handle to the file directly. Please note: if you use read(), you will be loading the whole file into memory.
More on passing iterators to HttpResonse. And I might be wrong, but I think you can drop the content-type.

Categories