文件上传是一种很常见的需要,在django中也是如此,比如用户头像。但是文件上传又分不同情况下的文件上传.
一种基于form表单file type,此时需要指定model中对应字段的upload路径。后台获取前端的数据后将文件路径保存到数据库,文件内容保存在upload指定的文件夹中。
另一种则是基于原生js的FormData(ajax本身好像不能传文件对象,目前没找到方法,知道的望告知), FormData传递文件对象,并通过XMLHttpRequest将页面全部信息传递到后端views中,后台读取文件内容并写入指定路径的指定文件中。如果前端需要地址,则需要在后台获取到文件地址后返回给前端。
基于原生js的文件上传:
index.html
因为使用FormData(),contentType, processData一定要设置为False
<!DOCTYPE html>
{% load staticfiles %}
<html>
<body>
<p>请输入两个数字</p>
<form action="" method="get" enctype="multipart/form-data">
{% csrf_token %}
a: <input type="text" id="a" name="a"> <br>
b: <input type="text" id="b" name="b"> <br>
头像:<input type="file" id="file" name="file"><br>
<p>a +b: <span id='result'></span></p>
<button type="button" id='sum'>提交</button>
</form>
<script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
<script>
$(document).ready(function () {
var form_data = new FormData(); //创建FormData对象
$("#sum").click(function () {
var a = $("#a").val();
var b = $("#b").val();
var file = $("#file")[0].files[0]; //获取文件对象,
form_data.append('a', a);
form_data.append('b', b);
form_data.append('file', file);
form_data.append('csrfmiddlewaretoken', "{{ csrf_token }}"); //带上csrf_token
$.ajax(
{
url: "{% url 'show' %}",
method: 'POST',
contentType: false,
processData: false,
data: form_data,
success: function (ret) {
$('#result').html(ret); //将计算结果填到标签内
}
}
)
});
});
</script>
</body>
</html>
views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def show(request):
if request.is_ajax():
a = int(request.POST.get('a'))
b = int(request.POST.get('b'))
res = a + b
file = request.FILES.get('file')
file_name = file.name # file 自带的属性,name
with open(file_name, 'wb') as f:
for line in file:
f.write(line)
return HttpResponse(res)
else:
return render(request, 'index.html')
此时提交后,因为没有指定保存文件的路径,所以就在项目的要目录下。
基于Django的简单文件上传
userinfo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户信息</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="username">
<input type="file" name="file">
<input type="submit" value="提交">
</form>
</body>
</html>
views.py
这里只简单的获取文件对象并写入文件,保存在根目录, file.chunks() 是将文件分割成块,内置方法。
def upload_file(request):
if request.method == 'GET':
return render(request, 'userinfo.html')
elif request.method == 'POST':
# 获取file文件名
file = request.FILES.get('file')
with open(file.name, 'wb') as f:
for chunk in file.chunks():
f.write(chunk)
return HttpResponse('ok')
基于Django form表单的文件上传
这里用到了modelform
forms.py
from django import forms
from .models import User
class UserModelForm(forms.ModelForm):
class Meta:
model = User
fields = '__all__'
models.py
from django.db import models
class User(models.Model):
username = models.CharField(verbose_name='用户名', max_length=32)
avatar = models.ImageField(verbose_name='头像', upload_to='uploads/')
这里注意要指定upload_to属性,即上传到哪个文件夹。
views.py
from django.shortcuts import render, HttpResponse
from django.views import View
from .forms import UserModelForm
class UploadFileView(View):
def get(self, request):
return render(request, 'userinfo.html')
def post(self, request):
avatar_form = UserModelForm(request.POST, request.FILES)
if avatar_form.is_valid():
avatar_form.save()
return HttpResponse('success')
else:
return HttpResponse('failed')
注意这里UserForm中要添加第二个参数:request.FILES, 因为文件对象在request.FILES中而不在request.POST中。
这样在前端提交后,文件被保存在uploads文件夹中。