如何使用Django上传文件
在本教程中,您将了解Django文件上传以及使用模型表单处理文件上传的概念。在这篇文章的最后,你会发现我使用的例子的源代码,所以你可以尝试和探索。
使用Django进行文件上传的基础知识
当文件提交到服务器时,文件数据最后放在request.FILES。
HTML表单必须设置 enctype="multipart/form-data" 属性。否则 request.FILES将为空。
表单必须使用POST方法提交。
Django有适当的模型字段来处理上传的文件:FileField和ImageField。
上传到FileField或ImageField不存储在数据库中但文件系统中的文件。
FileField并ImageField在数据库(通常为VARCHAR)中创建为字符串字段,其中包含对实际文件的引用。
如果删除包含的模型实例,FileField或者ImageFieldDjango 不会删除物理文件,而只能删除该文件的引用。
这request.FILES是一个类似字典的对象。每个键request.FILES都是来自的 <input type="file" name="" />。
每个值request.FILES都是一个UploadedFile实例。
您将需要设置MEDIA_URL并MEDIA_ROOT在项目的settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
在开发服务器中,您可以使用django.contrib.staticfiles.views.serve() 视图为用户上传的文件(媒体)提供服务。
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# Project url patterns...
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
要访问MEDIA_URL模板,你必须添加django.template.context_processors.media到你 context_processeors的TEMPLATES配置文件里面。
简单文件上传
以下是使用最少的文件上传示例FileSystemStorage。只用来了解流程的流程。
simple_upload.html
{% extends 'base.html' %}
{% load static %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="myfile">
<button type="submit">Upload</button>
</form>
{% if uploaded_file_url %}
<p>File uploaded at: <a href="{{ uploaded_file_url }}">{{ uploaded_file_url }}</a></p>
{% endif %}
<p><a href="{% url 'home' %}">Return to home</a></p>
{% endblock %}
views.py
from django.shortcuts import render
from django.conf import settings
from django.core.files.storage import FileSystemStorage
def simple_upload(request):
if request.method == 'POST' and request.FILES['myfile']:
myfile = request.FILES['myfile']
fs = FileSystemStorage()
filename = fs.save(myfile.name, myfile)
uploaded_file_url = fs.url(filename)
return render(request, 'core/simple_upload.html', {
'uploaded_file_url': uploaded_file_url
})
return render(request, 'core/simple_upload.html')
使用 Model Forms 上传文件
现在,这是一种更方便的方式。模型表单执行验证,自动构建上传的绝对路径,处理文件名冲突和其他常见任务。
models.py
from django.db import models
class Document(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.FileField(upload_to='documents/')
uploaded_at = models.DateTimeField(auto_now_add=True)
forms.py
from django import forms
from uploads.core.models import Document
class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ('description', 'document', )
views.py
def model_form_upload(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
form = DocumentForm()
return render(request, 'core/model_form_upload.html', {
'form': form
})
model_form_upload.html
{% extends 'base.html' %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
<p><a href="{% url 'home' %}">Return to home</a></p>
{% endblock %}
关于 FileField upload_to 参数
见下面的例子:
document = models.FileField(upload_to='documents/')
注意upload_to参数。文件将自动上传到MEDIA_ROOT/documents/。
也可以做如下事情:
document = models.FileField(upload_to='documents/%Y/%m/%d/')
上传的文件将被上传到 MEDIA_ROOT/documents/2016/08/01/。
该upload_to也可以是返回字符串的调用。此可调用接受两个参数,即实例和 文件名。
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'user_{0}/{1}'.format(instance.user.id, filename)
class MyModel(models.Model):
upload = models.FileField(upload_to=user_directory_path)
下载示例
这篇文章中使用的代码可以在Github上找到。
git clone https://github.com/sibtc/simple-file-upload.git
pip install django
python manage.py migrate
python manage.py runserver