1.上传文件按钮定制
一般文件上传的按钮都比较丑,我们可以通过下面的代码实现按钮样式的更换
views.py
def upload_file(request):
if request.method=="GET":
return render(request,'upload_file.html')
user = request.POST.get("user")
pwd = request.POST.get("pwd")
# 文件名
avator = request.FILES.get("customer_file")
with open(avator.name,'wb') as f:
for line in avator:
f.write(line)
return HttpResponse('上传成功')
上传文件
upload_file.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div style="position: relative;display: inline-block;height: 50px;min-width: 300px;overflow: hidden;">
<div style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;z-index: 1000;border: 1px dotted #9d9d9d;color: #9d9d9d;line-height: 50px;padding-left: 15px;">
<span>点击上传文件</span>
</div>
<input name="customer_file" type="file" id="excelFile"
style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;background-color: #333333;z-index: 1001;opacity: 0;filter:alpha(opacity=0);">
</div>
<div>
<input type="text" name="user">
<input type="submit" value="提交">
</div>
</form>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
$(function () {
$('#excelFile').change(function (e) {
// e.target得到的是input标签,e.target.files得到是一串filelist,
// e.target.files[0]得到的是图片的一些参数,这些参数可以根据自己的需要提取
var fileName = e.target.files[0].name;
$(this).prev().find('span').text(fileName);
})
})
</script>
</body>
</html>
View Code
# form表单的enctype设置为multipart/form-data后,表单中除了文件后台能拿到,其他值后台都拿不到。
1.1针对excel表格文件上传读取到数据库
models.py
class Excles(models.Model):
user = models.CharField(max_length=36)
age = models.IntegerField()
email = models.EmailField()
firm = models.CharField(max_length=36)
View Code
url.py
urlpatterns = [
path('admin/', admin.site.urls),
path('upload/', views.upload),
path('index/', views.index),
]
View Code
views.py
from django.shortcuts import render
from app01.models import Excles
def index(request):
return render(request,'index.html')
import xlrd
import os
def upload(request):
if request.method == "GET":
return render(request,'upload.html')
avatar = request.FILES.get('customer_excel')
print(type(avatar),avatar) # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> test.xlsx
print(type(avatar.name),avatar.name) # <class 'str'> test.xlsx
# 写入文件
with open(avatar.name, 'wb') as f:
for line in avatar:
f.write(line)
files = xlrd.open_workbook(avatar.name)
sheet = files.sheet_by_index(0) # 选取sheet1表格
row = sheet.nrows # 列表行数
mes_lis = []
for i in range(1,row):
rows = sheet.row_values(i) # 每行数据
rows_lis = Excles(user=rows[0], age=rows[1],email=rows[2],firm=rows[3])
mes_lis.append(rows_lis)
# bulk_create只能接收列表,用于批量写入数据
Excles.objects.bulk_create(mes_lis)
os.remove(avatar.name) # 移除这个表格
info = Excles.objects.all()
return render(request,'index.html',{'info':info})
View Code
upload.html
from django.shortcuts import render
from app01.models import Excles
def index(request):
return render(request,'index.html')
import xlrd
import os
def upload(request):
if request.method == "GET":
return render(request,'upload.html')
avatar = request.FILES.get('customer_excel')
print(type(avatar),avatar) # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> test.xlsx
print(type(avatar.name),avatar.name) # <class 'str'> test.xlsx
# 写入文件
with open(avatar.name, 'wb') as f:
for line in avatar:
f.write(line)
files = xlrd.open_workbook(avatar.name)
sheet = files.sheet_by_index(0) # 选取sheet1表格
row = sheet.nrows # 列表行数
mes_lis = []
for i in range(1,row):
rows = sheet.row_values(i) # 每行数据
rows_lis = Excles(user=rows[0], age=rows[1],email=rows[2],firm=rows[3])
mes_lis.append(rows_lis)
# bulk_create只能接收列表,用于批量写入数据
Excles.objects.bulk_create(mes_lis)
os.remove(avatar.name) # 移除这个表格
info = Excles.objects.all()
return render(request,'index.html',{'info':info})
View Code
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
<body>
<div class="container">
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<table class="table table-hover">
<thead>
<tr>
<th>序号</th>
<th>用户名</th>
<th>年龄</th>
<th>邮箱</th>
<th>公司</th>
</tr>
</thead>
<tbody>
{% for ret in info %}
<tr>
<td>{{ ret.pk }}</td>
<td>{{ ret.user }}</td>
<td>{{ ret.age }}</td>
<td>{{ ret.email }}</td>
<td>{{ ret.firm }}</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</body>
</html>
View Code
这个例子很简单,其中需要注意的几个点:
针对文件上传的视图函数中参数进行补充说明
avatar.name:这是一个属性,不是方法,该属性得到上传的文件名,包括后缀,如123.exe;
avatar.size:这也是一个属性,该属性得到上传文件的大小
myFile.read():从文件中读取整个上传的数据,这个方法只适合小文件;
myFile.chunks():按块返回文件,通过在for循环中进行迭代,可以将大文件按块写入到服务器中;
myFile.multiple_chunks():这个方法根据myFile的大小,返回True或者False,当myFile文件大于2.5M(默认为2.5M,可以调整)时,该方法返回True,否则返回False,因此可以根据该方法来选择选用read方法读取还是采用chunks方法:
针对bulk_create的使用说明
该方法是在django1.4版本之后才有的,针对文本文件的批量导入
create()每保存一条就执行一次SQL,而bulk_create()是执行一条SQL存入多条数据,会快很多
2.上传图片(针对较新版本浏览器)
上传图片和文件的区别主要在于图片上传上去,一方面要在前端显现出来,一方面还要存储在后端,而文件只是实现了单方面
案例:
默认图片(存放在/static/img路径下):
default.png
views.py
import os
import uuid # 生成一串随机数,用于给每个图片起随机名字
def upload_img(request):
if request.method == "GET":
return render(request,'upload_img.html')
avatar = request.POST.get('avatar')
# 图片名
print(avatar)
return HttpResponse('上传成功')
# 该函数是前端ajax来响应的
def form_data_upload(request):
"""
ajax上传文件
:param request:
:return:
"""
img_upload = request.FILES.get('img_upload')
# 图片名
print(">>>",img_upload)
# 修改后的图片名
file_name = str(uuid.uuid4()) + "." + img_upload.name.rsplit('.', maxsplit=1)[1]
# 图片路径,这里我创建了一个static文件,下面有创建了一个img文件,用于放置图片
img_file_path = os.path.join('static','img', file_name)
with open(img_file_path, 'wb') as f:
for line in img_upload.chunks():
f.write(line)
return HttpResponse(img_file_path)
View Code
模板一(createObjectURL):
upload_img.html
# URL.createObjectURL()方法会根据传入的参数创建一个指向该参数对象的URL. 这个URL的生命仅存在于它被创建的这个文档里. 新的对象URL指向执行的File对象或者是Blob对象。当不再需要这些 URL 对象时,每个对象必须通过调用 URL.revokeObjectURL()
方法来释放
createObjectURL技术参考点击此处
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="height: 100px;width: 100px;padding: 2px;border: 1px solid #dddddd;position: relative;">
{# 图片存储路径#}
<img style="height: 100%;width: 100%;border: 0;overflow: hidden;border-radius: 50%;"
id="previewImg"
{# 默认图片 #}
src="/static/img/default.png">
<input style="top: 0;left: 0;right: 0;bottom: 0;opacity: 0;position: absolute;z-index: 102;" id="avatarImg"
name="avatar_img" type="file" class="img-file"/>
</div>
<div>点击图片更换(<a href="#">撤销</a>)</div>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
<input type="text" name="avatar" id="avatar">
<input type="submit" value="提交">
</div>
</form>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
$(function () {
bindChangeAvatar1();
});
function bindChangeAvatar1() {
$('#avatarImg').change(function () {
var file_obj = $(this)[0].files[0];
// File对象,就是一个文件,比如我用input type="file"标签来上传文件,那么里面的每个文件都是一个File对象.
var blob = window.URL.createObjectURL(file_obj);
console.log(blob);
// Blob对象,就是二进制数据,比如通过new Blob()创建的对象就是Blob对象.又比如,在XMLHttpRequest里,
// 如果指定responseType为blob,那么得到的返回值也是一个blob对象.
// blob:http://127.0.0.1:8002/24b475b2-0de0-430b-a13d-e613ece37cd8
document.getElementById('previewImg').src = blob;
$('#previewImg').load(function () {
window.URL.revokeObjectURL(blob);
})
})
}
</script>
</body>
</html>
View Code
模板二(FileReader):
upload_img.html
# 使用FileReader对象的readAsDataURL方法可以将读取到的文件编码成Data URL。Data URL是一项特殊的技术,可以将资料(例如图片)内嵌在网页之中,不用放到外部文件。使用Data URL的好处是,您不需要额外再发出一个HTTP 请求到服务器端取得额外的资料,它适合应用在内嵌小图片。
FileReader技术参考连接点击此处
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="height: 100px;width: 100px;padding: 2px;border: 1px solid #dddddd;position: relative;">
{# 图片存储路径#}
<img style="height: 100%;width: 100%;border: 0;overflow: hidden;border-radius: 50%;"
id="previewImg"
{# 默认图片 #}
src="/static/img/default.png">
<input style="top: 0;left: 0;right: 0;bottom: 0;opacity: 0;position: absolute;z-index: 102;" id="avatarImg"
name="avatar_img" type="file" class="img-file"/>
</div>
<div>点击图片更换(<a href="#">撤销</a>)</div>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
<input type="text" name="avatar" id="avatar">
<input type="submit" value="提交">
</div>
</form>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
$(function () {
bindChangeAvatar2();
});
function bindChangeAvatar2() {
$('#avatarImg').change(function () {
var file_obj = $(this)[0].files[0];
console.log(file_obj);
// 获取文件对象,当中的值以键值对的形式存储
// File(352418) {name: "django生命周期.png", lastModified: 1531814882442,
// lastModifiedDate: Tue Jul 17 2018 16:08:02 GMT+0800 (中国标准时间),
// webkitRelativePath: "", size: 352418, …}
var reader = new FileReader();
reader.readAsDataURL(file_obj);
reader.onload = function (e) {
$('#previewImg')[0].src = this.result;
};
})
}
</script>
</body>
</html>
View Code
模板三(FormData,基于ajax实现文件上传):
upload_img.html
主流浏览器都开始支持一个叫做FormData的对象,有了这个FormData,可以实现利用ajax上传文件,
目前主流浏览器的较新版本都已经支持这个对象了,比如Chrome 7+、Firefox 4+、IE 10+、Opera 12+、Safari 5+
技术参考链接点击此处
# 通过 FormData.append()方法赋给字段的值若是数字会被自动转换为字符(字段的值可以是一个Blob对象,一个File对象,或者一个字符串,剩下其他类型的值都会被自动转换成字符串).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="height: 100px;width: 100px;padding: 2px;border: 1px solid #dddddd;position: relative;">
{# 图片存储路径#}
<img style="height: 100%;width: 100%;border: 0;overflow: hidden;border-radius: 50%;"
id="previewImg"
{# 默认图片 #}
src="/static/img/default.png">
<input style="top: 0;left: 0;right: 0;bottom: 0;opacity: 0;position: absolute;z-index: 102;" id="avatarImg"
name="avatar_img" type="file" class="img-file"/>
</div>
<div>点击图片更换(<a href="#">撤销</a>)</div>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
<input type="text" name="avatar" id="avatar">
<input type="submit" value="提交">
</div>
</form>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
$(function () {
bindChangeAvatar3();
});
function bindChangeAvatar3() {
$('#avatarImg').change(function () {
var file_obj = $(this)[0].files[0];
// 得到的是文件对象
console.log(file_obj);
// FormData的最大优点就是可以异步上传一个二进制文件
var form = new FormData();
// FormData {}
console.log(form);
// 创建一个空的FormData对象,然后再用append方法逐个添加键值对
form.append('img_upload', file_obj);
$.ajax({
url: '/form_data_upload/',
type:'POST',
data: form,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
success: function (arg) {
// arg,即后端发送过来的完整图片路径,
// static\img\53632381-9c69-4280-b8e6-e1dcc35df412.jpg
console.log(arg);
// 更换默认图片
$('#previewImg').attr('src',"/"+arg);
// input框显示图片路径
$('#avatar').val("/"+arg);
}
})
})
}
</script>
</body>
</html>
View Code
# 需要注意的是这里的模板响应了两个视图函数,一定要记得在url中配制好路径
3.上传图片(对浏览器兼容广泛)
views.py
USER_LIST = []
#通过index将列表中的数据渲染在主页
def index(request):
return render(request,'index.html',{'user_list':USER_LIST})
# 获取前端传来的用户名,密码,图片名称
def iframe_upload_img(request):
if request.method == "GET":
return render(request,'iframe_upload_img.html')
user = request.POST.get('user')
pwd = request.POST.get('pwd')
avatar = request.POST.get('avatar')
USER_LIST.append(
{
'user':user,
'pwd':pwd,
'avatar':avatar
}
)
# 重定向到主页
return redirect('/index/')
import json
import uuid # 获取随机字码
def upload_iframe(request):
ret = {'status':True,'data':None}
try:
avatar = request.FILES.get('avatar')
print(avatar)
file_name = str(uuid.uuid4()) + "." + avatar.name.rsplit('.', maxsplit=1)[1]
img_file_path = os.path.join('static', 'img', file_name)
with open(img_file_path, 'wb') as f:
for line in avatar.chunks():
f.write(line)
ret['data'] = os.path.join("/",img_file_path)
except Exception as e:
ret['status'] = False
ret['error'] = '上传失败'
return HttpResponse(json.dumps(ret))
# return JsonResponse(ret)
View Code
模板四(通过iframe伪异步上传):
iframe_upload_img.thml
# 在不支持html5的前提下,ajax技术是无法实现文件的异步上传,因为ajax本质上还是js写的。js不能操作浏览器端的主机,不能操作硬盘上的文件,所以无法上传文件,这里可以通过iframe内联框架,来伪装实现无页面的跳转的异步上传
# i通过frame伪异步上传,我们在上传文件的页面内联一个框架作为表单提交后的页面,同时把这个内联框架隐藏起来,伪造异步上传
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div style="height: 100px;width: 100px;padding: 2px;border: 1px solid #dddddd;position: relative;">
{# 这里给了个iframe标签,这个标签放置路径可以局部显示这个路径画面 #}
<iframe style="display: none;" id="ifr" name="fffff"></iframe>
<form method="POST" action="/upload_iframe/" enctype="multipart/form-data" target="fffff">
{% csrf_token %}
{# 默认图片 #}
<img style="height: 100px;width: 100px;border: 0;overflow: hidden;border-radius: 50%;" id="prevImg"
src="/static/img/default.png">
<input style="top: 0;left: 0;right: 0;bottom: 0;opacity: 0;position: absolute;z-index: 102;"
id="avatar"
name="avatar" type="file" class="img-file"/>
</form>
</div>
<form method="post" action="/iframe_upload_img/">
{% csrf_token %}
<input type="text" name="avatar" id="formAvatar" style="display: none">
<input type="text" name="user" placeholder="请输入用户名">
<input type="text" name="pwd" placeholder="请输入密码">
<input type="submit" value="提交">
</form>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
$(function () {
bindChangeAvatar4();
});
function bindChangeAvatar4() {
$('#avatar').change(function () {
// 父级是form表单
$(this).parent().submit();
// contentWindow 兼容各个浏览器,可取得子窗口的 window 对象。
$('#ifr')[0].onload = function () {
// 通过这种方式向iframe页面传递参数
var iframeContents = $('#ifr')[0].contentWindow.document.body.innerText;
iframeContents = JSON.parse(iframeContents);
console.log(iframeContents);
if (iframeContents.status) {
$('#prevImg').attr('src', iframeContents.data);
$('#formAvatar').val(iframeContents.data);
}
}
})
}
</script>
</body>
</html>
View Code
# 这里的模板对应两个form表单,分别对应两个视图函数