一、前端实现
- 定义一个
form
表单,然后指定属性enctype="multipart/form-data"
,不然无法上传文件; - 在上述表单中填入
input
组件,指定属性type="file"
。
以上代码示例如下:
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
</form>
二、后端实现
1.基本方法
Django会对接收的请求进行处理,于是在视图中可以直接从request
对象中,通过FILES
属性来获得上传的文件。在使用python
的文件I/O操作,来实现上传文件的存储。
示例代码:
# 可以定义一个函数,完成文件存储操作
def save_file(file,file_name):
with open(file_name,'wb') as fp:
for chunk in file.chunks():
fp.write(chunk)
def index(request):
if request.method == 'GET':
form = MyForm()
return render(request,'index.html',{'form':form})
else:
myfile = request.FILES.get('myfile')
save_file(myfile,"hello_world.txt")
return HttpResponse('上传成功')
通过
request.FILES
获得的对象是一个字典,可以通过前端组件指定的name
属性来获取特定的文件。
Django为文件对象附加了
chunks
方法,该方法以迭代器的形式返回固定大小的文件内容,避免一次性将数据读取到内存,主要用于处理大文件。
2.通过模型处理上传文件
定义模型的时候,可以使用字段FileField
存储文件,这个字段可以传递一个upload_to
参数,用来指定上传的文件保存的位置。即上传的文件不是直接保存在数据库中的,而是保存到字段指定的目录下的。
# models.py
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
thumbnail = models.FileField(upload_to='files')
# views.py
def index(request):
if request.method == 'GET':
return render(request,'index.html')
else:
title = request.POST.get('title')
content = request.POST.get('content')
thumbnail = request.FILES.get('thumbnail')
article = Article(title=title,content=content,thumbnail=thumbnail)
article = Article(title=title,content,thumbnail=thumbnai)
article.save()
return HttpResponse('success')
传入的
upload_to
参数是相对于项目目录下。如以上代码指定文件存储在项目下的files
文件夹内。
在创建的模型对象上调用完
save()
后,就会把文件保存到指定目录下,并会将这个文件的路径存储到数据库中。
注意:若要使用表单对上传的数据进行验证,则必须将
request.FILES
传入表单构造函数中。如:form = BlogForm(reuqest.POST,request.FILES)
否则表单无法读取上传的文件。
指定 MEDIA_ROOT 与 MEDIA_URL
可以在settings.py
中配置MEDIA_ROOT
参数,这样就不需要在FileField
中指定upload_to
参数了,文件会自动上传到MEDIA_ROOT
指定的目录下:
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
而MEDIA_URL
用来指定前端访问时,模板中变量{{ MEDIA_URL }}
访问的路径(相对于项目目录):
# settings.py
MEDIA_URL = '/media/'
# 项目文件夹的urls.py
from django.conf.urls.static import static
from django.conf import settings
urlpattern = [
path('',views.index),
] + static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
故
MEDIA_RROT
与MEDIA_URL
指向同一个文件夹。
若同时指定了
MEDIA_ROOT
与upload_to
参数,则文件会被上传到MEDIA_ROOT
下的upload_to
文件夹中。示例代码如下:class Article(models.Model): title = models.CharField(max_length=100) content = models.TextField() thumbnail = models.FileField(upload_to="%Y/%m/%d")
MDEDIA_URL的使用
配置MEDIA_URL
使得我们可以在前端模板中通过模板变量{{ MEDIA_URL }}
访问上传的文件,而要使用{{ MEDIA_URL }}
还需:
- 在配置文件配置
django.template.context_processors.media
:
# settings.py中
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.template.context_processors.media', # 配置项
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
DEBUG
模式下,还需在项目的urls.py
中配置路由:
# 项目文件夹的urls.py加入以下代码
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
三、限制上传的文件拓展名
若想限制上传的文件的拓展名,那么就需要使用表单。可以使用普通的Form
表单,也可以使用ModelForm
,字节从模型中读取字段。
示例代码:
# models.py
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
thumbnial = models.FileField(upload_to='%Y/%m/%d/',validators=[validators.FileExtensionValidator(['txt','pdf'])])
# form.py
class ArticleForm(form.ModelForm):
class Meta:
model = Article
fields = "__all__"
四、图片上传
图片上传与普通文件的上传是一样的,只不过 Django 就会判断上传的文件是否是图片格式(除了判断后缀名,还会判断是否是可用的图片)。若不是,则验证会失败。在定义模型的时候定义存储图片的字段ImageField
即可:
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
thumbnail = models.ImageField(upload_to='%Y/%m/%d/')
想要验证是否为合格的图片,直接使用ModelForm
就可以了:
class MyForm(form.ModelForm):
class Meta:
model = Article
fields = "__all__"
想要使用
ImageField
,需安装pillow
库。