Django - file upload and download

form upload form

 

Not so many thing, look at an example:
front-end code is important.

<div>
    <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} <input type="file" name="f1"> <input type="text" name="user"> <input type="submit" value="提交"> </form> </div> 

In general, when a normal form form submission, request header CONTENT_TYPE: application/x-www-form-urlencoded, and then the data is transmitted in the form of key-value pairs, the server from request.POSTthe value, no question, and CONTENT_TYPE: application/x-www-form-urlencodedthis type of encoding for most cases, everything pretty good.

And to say that the use of form form to upload a file, you have to say a few words up.
At first, the http protocol is not functional aspects upload files until rfc1867 add this functionality to the http protocol. Rfc1867 defined in the course of  formthe label  method must be  POST, enctype = "multipart/form-data" as well <input type = "file">.
So, when using the form form to upload documents, request header content_typeis multipart/form-datathis form, so we need to add a form tag enctype="multipart/form-dataattributes for identification.
If you can print request header to upload files, you will find CONTENT_TYPEis this content_type:multipart/form-data; boundary=----WebKitFormBoundarylZZyJUkrgm6h34DU, that boundary=----WebKitFormBoundarylZZyJUkrgm6h34DUwhat is it?
In multipart/form-data behind boundaryand a string of characters, this is the delimiter, a pile behind the randomly generated string, in order to prevent occurrence delimiter upload file server can not correctly identify the start of the file. That delimiter and dim it?
For the post request to upload a file, we did not use the original http protocol, so multipart / form-data request is based on the original http request method post comes, then it is said that the difference between this new way to post the request:

  1. Request a different head, a request for uploading files contentType = multipart/form-datais necessary, but post is not, after all, are not only upload files post ~.
  2. Different request body, is different here refers to the former (upload request) must be used between each field delimiter to separate the content transmission, such as contents and text files need spaced apart, otherwise the server there is no way the normal resolution file, which of course is no post delimiter directly key:valuetransmitted in the form it.

Of course, the curved around a few words can not explain clearly, we know how to use on the line.
Look views view of a process:

from django.shortcuts import render, redirect, HttpResponse
from django.db import transaction
def import_case(request, pk): """ 导入Excel数据,pk是所属项目的pk """ if request.method == 'POST': try: with transaction.atomic(): # 事物 # project_pk = request.POST.get("project_pk") # 数据库使用字段 excel = request.FILES.get('file_obj') book = xlrd.open_workbook(filename=None, file_contents=excel.read()) sheet = book.sheet_by_index(0) title = sheet.row_values(0) for row in range(1, sheet.nrows): print(sheet.row_values(row)) # 这里取出来每行的数据,就可以写入到数据库了 return HttpResponse('OK') except Exception as e: print(e) return render(request, 'import_case.html', {"project_pk": pk, "error": "上传文件类型有误,只支持 xls 和 xlsx 格式的 Excel文档"}) return render(request, 'import_case.html', {"project_pk": pk, "error": ""}) 

ajax upload files

 

The front end of the file:

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- ajax上传文件开始 --> <div> {% csrf_token %} <input type="file" id="ajaxFile"> <button id="ajaxBtn">上传</button> </div> <!-- ajax上传文件结束 --> </body> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script> console.log($("[name='csrfmiddlewaretoken']").val()); $("#ajaxBtn").click(function () { // 首先,实例化一个formdata对象 var formData = new FormData(); // 然后使用formdata的append来添加数据,即获取文件对象 // var file_obj = $("#ajaxFile")[0].files[0]; // 使用jQuery获取文件对象 var file_obj = document.getElementById('ajaxFile').files[0]; // 使用dom也行 formData.append('f1', file_obj ); // 处理csrftoken formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val()); // 也可以将其他的数据,以键值对的形式,添加到formData中 formData.append('user','张开'); $.ajax({ url: "/upload/", type: "POST", data: formData, processData:false, // contentType:false, success:function (dataMsg) { console.log(dataMsg); } }) }) </script> </html> 

Ajax set in order to avoid the contentType false request JQuery head content_typeoperates, thereby losing delimiter, the file server can not resolve properly.
In using jQuery $ .ajax () method when processData default parameter to true (which is a unique jQuery), the default will be the case of the data sequence transmitted to adapt default content type application / x-www-form -urlencoded
time if you want do not want to send information into the need to manually set it to false.
Let's look at the back-end views.pyhow to deal with:

import xlrd
from django.shortcuts import render
from django.http import JsonResponse def upload(request): if request.is_ajax(): # print(request.META['CONTENT_TYPE']) # multipart/form-data; boundary=----WebKitFormBoundaryuXDgAwSKKIGnITam # print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['mx1EBTtsOb0k96TUUW8XKbCGvK0Co3S6ZMlLvOuZOKAlO9nfhf6zol0V8KxRxbwT'], 'user': ['张开']}> # print(request.FILES) # <MultiValueDict: {'f1': [<InMemoryUploadedFile: 接口测试示例.xlsx (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)>]}> f1 = request.FILES.get('f1') print(f1) # 接口测试示例.xlsx book = xlrd.open_workbook(filename=None, file_contents=f1.read()) sheet = book.sheet_by_index(0) print(sheet.row_values(1)) # ['cnodejs项目', 'get /topics 主题首页', 'https://cnodejs.org/api/v1/topics', 'get', '', '{"success":true}'] return JsonResponse({"message": "upload successful"}) else: return render(request, 'upload.html') 

OK, say no good, dry would be finished.

download

 

Use StreamingHttpResponse

 

views in the main code:

from django.http import StreamingHttpResponse
def download(request): file=open('crm/models.py','rb') response =StreamingHttpResponse(file) response['Content-Type']='application/octet-stream' response['Content-Disposition']='attachment;filename="models.py"' return response 

Use FileResponse

 

views in the main code:

from django.http import FileResponse
def download(request): file=open('crm/models.py','rb') response =FileResponse(file) response['Content-Type']='application/octet-stream' response['Content-Disposition']='attachment;filename="models.py"' return response 

Filename can not solve the problems in Chinese

 

If you are careful to try, you will find two ways to download the above filenamecan not contain Chinese, then how to solve it? To look down!

from django.http import FileResponse
from django.utils.encoding import escape_uri_path   # 导入这个家伙 def download(request): file=open('crm/models.py','rb') response =FileResponse(file) response['Content-Type']='application/octet-stream' response['Content-Disposition']='attachment;filename="{}.py"'.format(escape_uri_path("我是中文啦")) return response 

It is not solved! perfect! !

form upload form

 

Not so many thing, look at an example:
front-end code is important.

<div>
    <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} <input type="file" name="f1"> <input type="text" name="user"> <input type="submit" value="提交"> </form> </div> 

In general, when a normal form form submission, request header CONTENT_TYPE: application/x-www-form-urlencoded, and then the data is transmitted in the form of key-value pairs, the server from request.POSTthe value, no question, and CONTENT_TYPE: application/x-www-form-urlencodedthis type of encoding for most cases, everything pretty good.

And to say that the use of form form to upload a file, you have to say a few words up.
At first, the http protocol is not functional aspects upload files until rfc1867 add this functionality to the http protocol. Rfc1867 defined in the course of  formthe label  method must be  POST, enctype = "multipart/form-data" as well <input type = "file">.
So, when using the form form to upload documents, request header content_typeis multipart/form-datathis form, so we need to add a form tag enctype="multipart/form-dataattributes for identification.
If you can print request header to upload files, you will find CONTENT_TYPEis this content_type:multipart/form-data; boundary=----WebKitFormBoundarylZZyJUkrgm6h34DU, that boundary=----WebKitFormBoundarylZZyJUkrgm6h34DUwhat is it?
In multipart/form-data behind boundaryand a string of characters, this is the delimiter, a pile behind the randomly generated string, in order to prevent occurrence delimiter upload file server can not correctly identify the start of the file. That delimiter and dim it?
For the post request to upload a file, we did not use the original http protocol, so multipart / form-data request is based on the original http request method post comes, then it is said that the difference between this new way to post the request:

  1. Request a different head, a request for uploading files contentType = multipart/form-datais necessary, but post is not, after all, are not only upload files post ~.
  2. Different request body, is different here refers to the former (upload request) must be used between each field delimiter to separate the content transmission, such as contents and text files need spaced apart, otherwise the server there is no way the normal resolution file, which of course is no post delimiter directly key:valuetransmitted in the form it.

Of course, the curved around a few words can not explain clearly, we know how to use on the line.
Look views view of a process:

from django.shortcuts import render, redirect, HttpResponse
from django.db import transaction
def import_case(request, pk): """ 导入Excel数据,pk是所属项目的pk """ if request.method == 'POST': try: with transaction.atomic(): # 事物 # project_pk = request.POST.get("project_pk") # 数据库使用字段 excel = request.FILES.get('file_obj') book = xlrd.open_workbook(filename=None, file_contents=excel.read()) sheet = book.sheet_by_index(0) title = sheet.row_values(0) for row in range(1, sheet.nrows): print(sheet.row_values(row)) # 这里取出来每行的数据,就可以写入到数据库了 return HttpResponse('OK') except Exception as e: print(e) return render(request, 'import_case.html', {"project_pk": pk, "error": "上传文件类型有误,只支持 xls 和 xlsx 格式的 Excel文档"}) return render(request, 'import_case.html', {"project_pk": pk, "error": ""}) 

ajax upload files

 

The front end of the file:

<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- ajax上传文件开始 --> <div> {% csrf_token %} <input type="file" id="ajaxFile"> <button id="ajaxBtn">上传</button> </div> <!-- ajax上传文件结束 --> </body> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script> console.log($("[name='csrfmiddlewaretoken']").val()); $("#ajaxBtn").click(function () { // 首先,实例化一个formdata对象 var formData = new FormData(); // 然后使用formdata的append来添加数据,即获取文件对象 // var file_obj = $("#ajaxFile")[0].files[0]; // 使用jQuery获取文件对象 var file_obj = document.getElementById('ajaxFile').files[0]; // 使用dom也行 formData.append('f1', file_obj ); // 处理csrftoken formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val()); // 也可以将其他的数据,以键值对的形式,添加到formData中 formData.append('user','张开'); $.ajax({ url: "/upload/", type: "POST", data: formData, processData:false, // contentType:false, success:function (dataMsg) { console.log(dataMsg); } }) }) </script> </html> 

Ajax set in order to avoid the contentType false request JQuery head content_typeoperates, thereby losing delimiter, the file server can not resolve properly.
In using jQuery $ .ajax () method when processData default parameter to true (which is a unique jQuery), the default will be the case of the data sequence transmitted to adapt default content type application / x-www-form -urlencoded
time if you want do not want to send information into the need to manually set it to false.
Let's look at the back-end views.pyhow to deal with:

import xlrd
from django.shortcuts import render
from django.http import JsonResponse def upload(request): if request.is_ajax(): # print(request.META['CONTENT_TYPE']) # multipart/form-data; boundary=----WebKitFormBoundaryuXDgAwSKKIGnITam # print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['mx1EBTtsOb0k96TUUW8XKbCGvK0Co3S6ZMlLvOuZOKAlO9nfhf6zol0V8KxRxbwT'], 'user': ['张开']}> # print(request.FILES) # <MultiValueDict: {'f1': [<InMemoryUploadedFile: 接口测试示例.xlsx (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)>]}> f1 = request.FILES.get('f1') print(f1) # 接口测试示例.xlsx book = xlrd.open_workbook(filename=None, file_contents=f1.read()) sheet = book.sheet_by_index(0) print(sheet.row_values(1)) # ['cnodejs项目', 'get /topics 主题首页', 'https://cnodejs.org/api/v1/topics', 'get', '', '{"success":true}'] return JsonResponse({"message": "upload successful"}) else: return render(request, 'upload.html') 

OK, say no good, dry would be finished.

download

 

Use StreamingHttpResponse

 

views in the main code:

from django.http import StreamingHttpResponse
def download(request): file=open('crm/models.py','rb') response =StreamingHttpResponse(file) response['Content-Type']='application/octet-stream' response['Content-Disposition']='attachment;filename="models.py"' return response 

Use FileResponse

 

views in the main code:

from django.http import FileResponse
def download(request): file=open('crm/models.py','rb') response =FileResponse(file) response['Content-Type']='application/octet-stream' response['Content-Disposition']='attachment;filename="models.py"' return response 

Filename can not solve the problems in Chinese

 

If you are careful to try, you will find two ways to download the above filenamecan not contain Chinese, then how to solve it? To look down!

from django.http import FileResponse
from django.utils.encoding import escape_uri_path   # 导入这个家伙 def download(request): file=open('crm/models.py','rb') response =FileResponse(file) response['Content-Type']='application/octet-stream' response['Content-Disposition']='attachment;filename="{}.py"'.format(escape_uri_path("我是中文啦")) return response 

It is not solved! perfect! !

Guess you like

Origin www.cnblogs.com/zhang-da/p/12575566.html