Example of Django file download function: django File Download
For a Django-based website that provides the file download function, the simplest way is to hand over static files to Nginx for processing. However, sometimes, due to the website logic, you must use Django to provide download functions, such as page data export (download dynamically generated files), check user permissions before downloading files. Therefore, it is necessary to study the implementation of the file download function in Django.
Implementation of the simplest file download function
Put the file stream into the HttpResponse object, for example:
def file_download(request): # do something... with open('file_name.txt') as f: c = f.read() return HttpResponse(c)
This method is simple and crude, and is suitable for downloading small files. However, if this file is very large, it will occupy a large amount of memory and even cause server crashes.
More Reasonable File Download Functions
Django's HttpResponse object allows you to use the iterator as an input parameter. You can replace the input parameter c in the above Code with an iterator to optimize the above download function to be suitable for all file sizes; furthermore, Django recommends replacing the HttpResponse object with the StreamingHttpResponse object. The StreamingHttpResponse object is used to send the file stream to the browser, which is very similar to the HttpResponse object. For the file download function, it is more reasonable to use the streaminghttprespon.
Therefore, a more reasonable file download function should first write an iterator for processing files, and then pass the iterator as a parameter to the StreaminghttpResponse object, such:
from django.http import StreamingHttpResponsedef big_file_download(request): # do something... def file_iterator(file_name, chunk_size=512): with open(file_name) as f: while True: c = f.read(chunk_size) if c: yield c else: break the_file_name = "file_name.txt" response = StreamingHttpResponse(file_iterator(the_file_name)) return response
File Download function optimized again
The above code has completed the transfer of files on the server to the browser through the file, but the file flow is usually displayed in the form of garbled code in the browser, rather than downloaded to the hard disk, therefore, we also need to optimize it to write the file stream to the hard disk. The optimization is simple. Just assign the following values to the Content-Type and Content-Disposition fields of the StreamingHttpResponse object, for example:
response['Content-Type'] = 'application/octet-stream'response['Content-Disposition'] = 'attachment;filename="test.pdf"'
The complete code is as follows:
from django.http import StreamingHttpResponsedef big_file_download(request): # do something... def file_iterator(file_name, chunk_size=512): with open(file_name) as f: while True: c = f.read(chunk_size) if c: yield c else: break the_file_name = "big_file.pdf" response = StreamingHttpResponse(file_iterator(the_file_name)) response['Content-Type'] = 'application/octet-stream' response['Content-Disposition'] = 'attachment;filename="{0}"'.format(the_file_name) return response
Specific exported file format
Export an Excel table
1. Export an Excel table directly
First, obtain the data to be exported and save it as a list.
Then, write the data to the Excel file and return it to the page as a stream for download.
Import xlwtimport ioimport jsonfrom django. http import HttpResponsedef set_style (name, height, bold = False): style = xlwt. XFStyle () # initialize the style font = xlwt. font () # create a font for the style. name = name # 'times New Roman 'font. bold = bold font. color_index = 000 font. height = height style. font = font # Set the cell border # borders = xlwt. borders () # borders. left = 6 # borders. right = 6 # borders. top = 6 # borders. bottom = 6 # style. Borders = borders # Set the cell background color # pattern = xlwt. pattern () # set the pattern to the actual type # Pattern. pattern = pattern. SOLID_PATTERN # Set the cell background color # pattern. pattern_fore_colour = 0x00 # style. pattern = pattern return styledef write_excel (data, name, header): # open an Excel Workbook file = xlwt. workbook () # create a new sheet. If you operate on a cell repeatedly, an exception is thrown. Therefore, the cell_overwrite_ OK parameter is added to True table = file. add_sheet (name, cell_overwrite_ OK = True) if data is Non E: return file # Write the title bar row0 = [u 'business', u 'status', u 'beijing', u 'shanghai', u 'shanghai', u 'shenzhen ', u'state subtotal '] for I in range (0, len (row0): table. write_merge (0, 0, I, I, row0 [I], set_style ('times New Roman ', 220, True) table. write_merge (0, 2, 7, 9, "cell merge", set_style ('times New Roman ', 220, True) "table. write_merge (x, x + m, y, w + n, string, sytle) x indicates rows, y indicates columns, m indicates the number of Cross rows, and n indicates the number of Cross columns, string indicates the content of the cell to be written, and style indicates the cell style. Where, x, y, w, and h are all calculated starting with 0. "L = 0 n = len (header) # Write data for line in data: for I in range (n): table. write (l, I, line [header [I]) l + = 1 # Save the file directly # file. save ("D:/excel_name.xls") # Write IO res = get_excel_stream (file) # Set the HttpResponse type response = HttpResponse (content_type = 'application/vnd. ms-excel ') from urllib import parse response ['content-disposition'] = 'attachment; filename =' + parse. quote ("excel_name") + '.xls '# stream files Write to response and return response. write (res) return responsedef get_excel_stream (file): # The StringIO operation can only be str. If you want to operate binary data, you need to use BytesIO. Excel_stream = io. bytesIO () # this is very important. It is not to save the file name, but a BytesIO stream (read and write in memory) to the save Function. save (excel_stream) # The getvalue method is used to obtain the written bytes and return the result to re res = excel_stream.getvalue () excel_stream.close () return res
2. Export a json File
Exporting a json file is not as troublesome as Excel. You only need to splice json data and directly export the file to a local file. However, exporting the file to a webpage does not save the file to a local file like exporting an excel file, directly return the stream?
Def write_json (data): try: json_stream = get_json_stream (data) response = HttpResponse (content_type = 'application/json ') from urllib import parse response ['content-disposition'] = 'attachment; filename = '+ parse. quote ("test") + '. json 'response. write (json_stream) return response t Exception as e: print (e) def get_json_stream (data): # At the beginning, I always encounter errors when using ByteIO streams, but later, with reference to the Liao Xuefeng website, there was no problem with using StringIO file = io. stringIO () data = json. dumps (data) file. write (data) res = file. getvalue () file. close () return res
3. Export the compressed package
Because both files cannot be exported at the same time, you need to put these two files into the package and then return the package as a stream.
Thinking? How can I write the two file streams into the zip package? It seems unreasonable. Later, under the guidance of the boss, the files to be packaged will be saved to the local device, packaged into a zip file, deleted the local file, and then read the zip file stream and write it to response, returns the zip file stream.
Def write_zip (e_data, j_data, export_name): try: # Save to a local file # Return the file name, note the differences between the Save method and the exported json and excel files. j_name = write_json (j_data, export_name [1]) e_name = write_excel (e_data, export_name [1]) # Write the local file to zip, rename it, and delete the local temporary file z_name1_'export.zip 'z_file = zipfile. zipFile (z_name, 'w') z_file.write (j_name) z_file.write (e_name) OS. remove (j_name) OS. remove (e_name) z_file.close () # Read the zip file again and return the file stream. However, z_file = open (z_name, 'rb') must be opened in binary mode ') data = z_file.read () z_file.close () OS. remove (z_file.name) response = HttpResponse (data, content_type = 'application/zip') from urllib import parse response ['content-disposition'] = 'attachment; filename = '+ parse. quote (z_name) return response failed t Exception as e: logging. error (e) print (e)
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.