如何使用Django上传文件

2017-10-20

如何使用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_processeorsTEMPLATES配置文件里面。


简单文件上传

以下是使用最少的文件上传示例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
https://simpleisbetterthancomplex.com/tutorial/2016/08/01/how-to-upload-files-with-django.html