I'm trying to write a custom django backend that writes the contents of an uploaded file to an output file while also saving the file as it normally would. I assumed I could do this by overriding the _open function of Django, but no luck. Anyone know how to accomplish this? Here's what I've been messing around with
from django.core.files.storage import FileSystemStorage
class TestStore(FileSystemStorage):
def _open(self, name, mode='rb'):
data = open(name, 'rb')
dataRead = data.read()
filename = '/home/somewhere/testdir/output.txt'
FILE = open(filename, 'w')
FILE.write(dataRead)
FILE.close()
data.close()
return name
If you already created the file you can just output it with content-disposition:
response = HttpResponse(data, content_type='text/txt')
response['Content-Disposition'] = 'attachment; filename=filename'
Related
I am using fine-uploader.js and fine-uploader.css for uploading my files using web2py framework.
The callback in the controller is
def upload_callback():
if 'qqfile' in request.vars:
filename = request.vars.qqfile
newfilename = db.doc.filename.store(request.body, filename)
db.doc.insert(filename=newfilename,uploaded_by=auth.user.id)
return response.json({'success': 'true'})
The Model
uploadfolder = os.path.join(request.folder, 'uploads')
db.define_table('doc',
Field('name', requires = IS_NOT_EMPTY()),
Field('filename', 'upload',autodelete=True,uploadfolder=uploadfolder),
Field('uploaded_by', db.auth_user)
)
When I upload file 'test01.xls', web2py stores it in file "doc.filename.bfbf907529358f82.7830302729.txt"
I do not understand why the extension xls is being changed to txt. I have also tried uploading a jpg file. Web2py changes the extension of the uploaded file to txt. Can somebody help me.
As request.vars.qqfile is not the filename but a cgi.FieldStorage object, you cannot use it as the filename but must instead extract the filename from it:
filename = request.vars.qqfile.filename
Alternatively, you can simply pass the FieldStorage object directly to the .insert method, and web2py will automatically handle extracting the filename and saving the file:
def upload_callback():
if 'qqfile' in request.vars:
db.doc.insert(filename=request.vars.qqfile, uploaded_by=auth.user.id)
return response.json({'success': 'true'})
I am trying to create a new file and then write some content to it just to create a basic backup of a template.
When I log out the values of filename and file_content they are correct, but when I send the data all I get is a file named after the method (download_include) and a fixnum inside the file, the last one made was 15.
# POST /download_include/:id
def download_include
#include = Include.find(params[:id])
version_to_download = #include.latest_version_record
filename = "#{version_to_download.name}"
file_content = "#{version_to_download.liquid_code.to_s}"
file = File.open(filename, "w") { |f| f.write (file_content) }
send_data file
end
I also tried send_file but that produces the error
no implicit conversion of Fixnum into String
I also tried to just write dummy values like below, and it still produced a file named after the method with a fixnum inside it.
file = File.open("DOES THIS CHANGE THE FILENAME?", "w") { |f| f.write ("FILE CONTENT?") }
I feel I am missing something obvious but I cannot figure it out after looking at many examples here and in blogs.
If you don't end along the filename as an option for send_data, it defaults to the method name.
Secondly, the download wants to read the data from a buffer. My guess is your syntax is just sending a file handle.
Try this...
send_data(file.read, filename: filename)
Or skip the intermediate file and try...
send_data(version_to_download.liquid_code.to_s, filename: filename)
My App saves Files to the Filesystem via an base64 encoded API. Here is my (simplified) controller:
def create
file = "name.pdf"
folder = "downloads"
FileUtils::mkdir_p folder
f = File.open File.join(folder, file), "wb"
if f.write Base64.decode64(params[:file])
f.close
end
Now I want to test for an actual file creation. How do I check whether there is a file or not?
Thanks for your input!
I am using spreadsheet gem to generate .xls file. After writing it to a file, I am trying to send to client browser for download.
Below is the code in rails
workbook = Spreadsheet::Workbook.new
# Constructed the data
file = "/path/to/file/sheet.xls"
workbook.write file
send_file file
This file when opened contains expected data in ideal format.
Below is the code in js:
CustomRestService.custom_post("report",{report_data: angular.toJson($scope.report_data)},"download_xls",{}).then (data)->
if data
hiddenElement = document.createElement('a')
angular.element(document.body).append(hiddenElement)
hiddenElement.href = 'data:attachment/xls,' + encodeURI(data)
hiddenElement.target = '_blank'
hiddenElement.download = "report.xls"
hiddenElement.click()
hiddenElement.remove()
But the file getting downloaded in browser contains junk data. I tried multiple solutions like below:
Using send_data, instead of send_file
Generated xls data and wrote to StringIO object to directly download
Constructed Blob object in js, with type as "application/vnd.ms-excel" and trying to download it.
All attempts failed, as I am missing something. All suggestions are welcome.
filename = "/path/to/file/sheet.xls"
tempfile = Tempfile.new(filename)
workbook = Spreadsheet::Workbook.new
...
workbook.write(tempfile.path)
send_file tempfile.path, :filename => filename
I have this code, which writes a zip file to disk, reads it back, uploads to s3, then deletes the file:
compressed_file = some_temp_path
Zip::ZipOutputStream.open(compressed_file) do |zos|
some_file_list.each do |file|
zos.put_next_entry(file.some_title)
zos.print IO.read(file.path)
end
end # Write zip file
s3 = Aws::S3.new(S3_KEY, S3_SECRET)
bucket = Aws::S3::Bucket.create(s3, S3_BUCKET)
bucket.put("#{BUCKET_PATH}/archive.zip", IO.read(compressed_file), {}, 'authenticated-read')
File.delete(compressed_file)
This code works already but what I want is to not create the zip file anymore, to save a few steps. I was wondering if there is a way to export the zipfile data directly to s3 without having to first create a tmpfile, read it back, then delete it?
I think I just found the answer to my question.
It's Zip::ZipOutputStream.write_buffer. I'll check this out and update this answer when I get it working.
Update
It does work. My code is like this now:
compressed_filestream = Zip::ZipOutputStream.write_buffer do |zos|
some_file_list.each do |file|
zos.put_next_entry(file.some_title)
zos.print IO.read(file.path)
end
end # Outputs zipfile as StringIO
s3 = Aws::S3.new(S3_KEY, S3_SECRET)
bucket = Aws::S3::Bucket.create(s3, S3_BUCKET)
compressed_filestream.rewind
bucket.put("#{BUCKET_PATH}/archive.zip", compressed_filestream.read, {}, 'authenticated-read')
The write_buffer returns a StringIO and needs to rewind the stream first before reading it. Now I don't need to create and delete the tmpfile.
I'm just wondering now if write_buffer would be more memory extensive or heavier than open? Or is it the other way around?