Django文件上传需要考虑的重要事项

文件或图片一般通过表单进行。用户在前端点击文件上传,然后以POST方式将数据和文件提交到服务器。服务器在接收到POST请求后需要将其存储在服务器上的某个地方。Django默认的存储地址是相对于根目录的/media/文件夹,存储的默认文件名就是文件本来的名字。上传的文件如果不大于2.5MB,会先存入服务器内存中,然后再写入磁盘。如果上传的文件很大,Django会把文件先存入临时文件,再写入磁盘。

Django默认处理方式会出现一个问题,所有文件都存储在一个文件夹里。不同用户上传的有相同名字的文件可能会相互覆盖。另外用户还可能上传一些不安全的文件如js和exe文件,我们必需对允许上传文件的类型进行限制。因此我们在利用Django处理文件上传时必需考虑如下3个因素:

设置存储上传文件的文件夹地址

对上传文件进行重命名

对可接受的文件类型进行限制(表单验证)

注意:以上事项对于上传图片是同样适用的。

Django文件上传的3种常见方式

Django文件上传一般有3种方式(如下所示)。我们会针对3种方式分别提供代码示范。

使用一般的自定义表单上传,在视图中手动编写代码处理上传的文件

使用由模型创建的表单(ModelForm)上传,使用form.save()方法自动存储

使用Ajax实现文件异步上传,上传页面无需刷新即可显示新上传的文件

项目创建与设置

我们先使用django-admin startproject命令创建一个叫file_project的项目,然后cd进入file_project, 使用python manage.py startapp创建一个叫file_upload的app。

我们首先需要将file_upload这个app加入到我们项目里,然后设置/media/和/STATIC_URL/文件夹。我们上传的文件都会放在/media/文件夹里。我们还需要使用css和js这些静态文件,所以需要设置STATIC_URL。

#file_project/settings.py

INSTALLED_APPS = [

'django.contrib.admin',

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.messages',

'django.contrib.staticfiles',

'file_upload',# 新增

]

STATIC_URL = '/static/'

STATICFILES_DIRS = [os.path.join(BASE_DIR, "static"), ]

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

MEDIA_URL = '/media/'

#file_project/urls.py

from django.contrib import admin

from django.urls import path, include

from django.conf import settings

from django.conf.urls.static import static

urlpatterns = [

path('admin/', admin.site.urls),

path('file/', include("file_upload.urls")),

] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

创建模型

使用Django上传文件创建模型不是必需,然而如果我们需要对上传文件进行系统化管理,模型还是很重要的。我们的File模型包括file和upload_method两个字段。我们通过upload_to选项指定了文件上传后存储的地址,并对上传的文件名进行了重命名。

#file_upload/models.py

from django.db import models

import os

import uuid

# Create your models here.

# Define user directory path

def user_directory_path(instance, filename):

ext = filename.split('.')[-1]

filename = '{}.{}'.format(uuid.uuid4().hex[:10], ext)

return os.path.join("files", filename)

class File(models.Model):

file = models.FileField(upload_to=user_directory_path, null=True)

upload_method = models.CharField(max_length=20, verbose_name="Upload Method")

注意:如果你不使用ModelForm,你还需要手动编写代码存储上传文件。

URLConf配置

本项目一共包括3个urls, 分别对应普通表单上传,ModelForm上传和显示文件清单。

#file_upload/urls.py

from django.urls import re_path, path

from . import views

# namespace

app_name = "file_upload"

urlpatterns = [

# Upload File Without Using Model Form

re_path(r'^upload1/$', views.file_upload, name='file_upload'),

# Upload Files Using Model Form

re_path(r'^upload2/$', views.model_form_upload, name='model_form_upload'),

# View File List

path('file/', views.file_list, name='file_list'),

]

使用一般表单上传文件

我们先定义一个一般表单FileUploadForm,并通过clean方法对用户上传的文件进行验证,如果上传的文件名不以jpg, pdf或xlsx结尾,将显示表单验证错误信息。关于表单的自定义和验证更多内容见Django基础: 表单forms的设计与使用。

#file_upload/forms.py

from django import forms

from .models import File

# Regular form

class FileUploadForm(forms.Form):

file = forms.FileField(widget=forms.ClearableFileInput(attrs={'class': 'form-control'}))

upload_method = forms.CharField(label="Upload Method", max_length=20,

widget=forms.TextInput(attrs={'class': 'form-control'}))

def clean_file(self):

file = self.cleaned_data['file']

ext = file.name.split('.')[-1].lower()

if ext not in ["jpg", "pdf", "xlsx"]:

raise forms.ValidationError("Only jpg, pdf and xlsx files are allowed.")

# return cleaned data is very important.

return file

注意: 使用clean方法对表单字段进行验证时,别忘了return验证过的数据,即cleaned_data。只有返回了cleaned_data, 视图中才可以使用form.cleaned_data.get(‘xxx')获取验证过的数据。

对应一般文件上传的视图file_upload方法如下所示。当用户的请求方法为POST时,我们通过form.cleaned_data.get('file')获取通过验证的文件,并调用自定义的handle_uploaded_file方法来对文件进行重命名,写入文件。如果用户的请求方法不为POST,则渲染一个空的FileUploadForm在upload_form.html里。我们还定义了一个file_list方法来显示文件清单。

#file_upload/views.py

from django.shortcuts import render, redirect

from .models import File

from .forms import FileUploadForm, FileUploadModelForm

import os

import uuid

from django.http import JsonResponse

from django.template.defaultfilters import filesizeformat

# Create your views here.

# Show file list

def file_list(request):

files = File.objects.all().order_by("-id")

return render(request, 'file_upload/file_list.html', {'files': files})

# Regular file upload without using ModelForm

def file_upload(request):

if request.method == "POST":

form = FileUploadForm(request.POST, request.FILES)

if form.is_valid():

# get cleaned data

upload_method = form.cleaned_data.get("upload_method")

raw_file = form.cleaned_data.get("file")

new_file = File()

new_file.file = handle_uploaded_file(raw_file)

new_file.upload_method = upload_method

new_file.save()

return redirect("/file/")

else:

form = FileUploadForm()

return render(request, 'file_upload/upload_form.html',

{'form': form, 'heading': 'Upload files with Regular Form'}

)

def handle_uploaded_file(file):

ext = file.name.split('.')[-1]

file_name = '{}.{}'.format(uuid.uuid4().hex[:10], ext)

# file path relative to 'media' folder

file_path = os.path.join('files', file_name)

absolute_file_path = os.path.join('media', 'files', file_name)

directory = os.path.dirname(absolute_file_path)

if not os.path.exists(directory):

os.makedirs(directory)

with open(absolute_file_path, 'wb+') as destination:

for chunk in file.chunks():

destination.write(chunk)

return file_path

注意:

handle_uploaded_file方法里文件写入地址必需是包含/media/的绝对路径,如果/media/files/xxxx.jpg,而该方法返回的地址是相对于/media/文件夹的地址,如/files/xxx.jpg。存在数据中字段的是相对地址,而不是绝对地址。

构建文件写入绝对路径时请用os.path.join方法,因为不同系统文件夹分隔符不一样。写入文件前一个良好的习惯是使用os.path.exists检查目标文件夹是否存在,如果不存在先创建文件夹,再写入。

上传表单模板upload_form.html代码如下:

#file_upload/templates/upload_form.html

{% extends "file_upload/base.html" %}

{% block content %}

{% if heading %}

{{ heading }}

{% endif %}

{% csrf_token %}

{{ form.as_p }}

Upload

{% endblock %}

显示文件清单模板file_list.html代码如下所示:

# file_upload/templates/file_list.html

{% extends "file_upload/base.html" %}

{% block content %}

File List

RegularFormUpload | ModelFormUpload

| AjaxUpload

{% if files %}

Filename & URL Filesize Upload Method

{% for file in files %}

{{ file.file.url }}{{ file.file.size | filesizeformat }}{{ file.upload_method }}

{% endfor %}

{% else %}

No files uploaded yet. Please click here

to upload files.

{% endif %}

{% endblock %}

注意:

对于上传的文件我们可以调用file.url, file.name和file.size来查看上传文件的链接,地址和大小。

上传文件的大小默认是以B显示的,数字非常大。使用Django模板过滤器filesizeformat可以将文件大小显示为人们可读的方式,如MB,KB。

使用ModelForm上传文件

使用ModelForm上传是小编我推荐的上传方式,前提是你已经在模型中通过upload_to选项自定义了用户上传文件存储地址,并对文件进行了重命名。我们首先要自定义自己的FileUploadModelForm,由File模型重建的。代码如下所示:

#file_upload/forms.py

from django import forms

from .models import File

# Model form

class FileUploadModelForm(forms.ModelForm):

class Meta:

model = File

fields = ('file', 'upload_method',)

widgets = {

'upload_method': forms.TextInput(attrs={'class': 'form-control'}),

'file': forms.ClearableFileInput(attrs={'class': 'form-control'}),

}

def clean_file(self):

file = self.cleaned_data['file']

ext = file.name.split('.')[-1].lower()

if ext not in ["jpg", "pdf", "xlsx"]:

raise forms.ValidationError("Only jpg, pdf and xlsx files are allowed.")

# return cleaned data is very important.

return file

使用ModelForm处理文件上传的视图model_form_upload方法非常简单,只需调用form.save()即可,无需再手动编写代码写入文件。

#file_upload/views.py

from django.shortcuts import render, redirect

from .models import File

from .forms import FileUploadForm, FileUploadModelForm

import os

import uuid

from django.http import JsonResponse

from django.template.defaultfilters import filesizeformat

# Create your views here.

# Upload File with ModelForm

def model_form_upload(request):

if request.method == "POST":

form = FileUploadModelForm(request.POST, request.FILES)

if form.is_valid():

form.save() # 一句话足以

return redirect("/file/")

else:

form = FileUploadModelForm()

return render(request, 'file_upload/upload_form.html',

{'form': form,'heading': 'Upload files with ModelForm'}

)

模板跟前面一样,这里就不展示了。

GitHub源码地址

小结

本文提供并解读了利用Django上传文件的3种主要方式(一般表单上传,ModelForm上传和Ajax上传)及示范代码。

以上就是django上传文件的三种方式的详细内容,更多关于django上传文件的资料请关注脚本之家其它相关文章!

django文件上传到服务器,django上传文件的三种方式相关推荐

  1. 一个服务器同时运行多个网站三种方式

    一个服务器同时运行多个网站三种方式有三种方式:1.IP一样,端口不一样 2.端口一样IP不一样 3.端口一样,IP一样,绑定的域名不一样 第一种最简单,只需要在新建网站的时候修改端口,一般改为8080 ...

  2. java文件与bean所定义的_Spring定义bean的三种方式和自动注入

    前言:随着一个项目规模的增大,我们不得不引入许多Java bean对象,而这些对象一般来说是在Spring的配置文件applicationContext.xml中进行配置的,这样就声明了这是一个由Sp ...

  3. 电脑上的文件怎么传到服务器,电脑上文件怎么传到云服务器

    电脑上文件怎么传到云服务器 内容精选 换一换 当服务器A和服务器B同时挂载同一文件系统C时,在服务器A上传文件,服务器B同步此文件时存在延时,而单独上传至服务器B则没有延时.需要在两个服务器的挂载参数 ...

  4. ajax上传多文件和数据,Ajax上传数据和上传文件(三种方式)

    Ajax向后端发送数据可以有三种方式:原生Ajax方式,jQuery Ajax方式,iframe+form 方式(伪造Ajax方式) Title .btn { background-color: co ...

  5. php fs 上传文件,PHP操作GridFS存储文件到MongoDB的三种方式

    一般情况采取第一种方法,直接传文件,第二种方法适合生成的数据不用保存到本地再上传而是直接以二进制存到MongoDB,第三种方式是直接把表单上传的文件存进MongoDB. //初始化gridfs $co ...

  6. 文件上传的三种方式-Java

    前言:负责,因为该项目他(jetty嵌入式开始SpringMvc)实现文件上传的必要性,并拥有java文件上传这一块还没有被曝光.并 Http 更多晦涩协议.因此,这种渐进的方式来学习和实践上载文件的 ...

  7. 怎么把本地的文件传给服务器,怎么把本地文件传给云服务器

    怎么把本地文件传给云服务器 内容精选 换一换 本文介绍如何在 Linux 系统的本地机器上使用 FTP 服务,将文件从本地上传到云服务器中.已在待上传文件的云服务器中搭建 FTP 服务.如果您的云服务 ...

  8. Qt三种方式实现FTP上传功能

    FTP协议 FTP的中文名称是"文件传输协议",是File Transfer Protocol三个英文单词的缩写.FTP协议是TCP/IP协议组中的协议之一,其传输效率非常高,在网 ...

  9. 云服务器怎么和自己的电脑传文件,电脑和云服务器之间怎么传文件

    电脑和云服务器之间怎么传文件 内容精选 换一换 当创建文件系统后,您需要使用云服务器来挂载该文件系统,以实现多个云服务器共享使用文件系统的目的.本章节以Windows 2012版本操作系统为例进行CI ...

最新文章

  1. magento2 所需要php 扩展,Magento2系统环境要求与安装分享
  2. Docker swarm 笔记
  3. 西安石油大学计算机基础考试试题,2017年西安石油大学计算机学院824计算机组成原理考研题库...
  4. 一个程序员如何做到结构上胸有成竹
  5. 流行歌单片机c语言编程,单片机6首音乐播放的proteus仿真电路及C语言程序设计...
  6. 强大的漏洞扫描工具--nessus
  7. C# 如何理解 ASP.NET Web API 的 REST
  8. python 玩公众号游戏_从零基础开始,用python手把手教你玩跳一跳小游戏,直接打出高分...
  9. python phpstudy_phpStudy后门分析及复现
  10. SQL点点滴滴_常用函数
  11. C++ eof()函数相关应用技巧分享
  12. xsd是什么文件,作用是什么?
  13. matlab希尔伯特变换,希尔伯特变换和傅里叶变换MATLAB仿真
  14. 硬件驱动为什么要有WHQL数字签名
  15. WIFI手机使用正常电脑使用卡顿解决方案
  16. 1977-1998全国历年高考状元现状
  17. 软件工程大作业:自动售货机系统
  18. OL3-Cesium 二三维鼠标事件统一处理
  19. zj-layout组件的布局
  20. Linux简介及在VMware上安装第一台虚拟机

热门文章

  1. 哈希(Hash) - 开散列/闭散列
  2. 这些学校可以查考研成绩排名!
  3. java简单的Scanner输入工具源码
  4. uniapp通过url带参数传值
  5. kail 暴力破解excel密码
  6. [iBoard 电子学堂][第二卷 C程序设计语言 ]第一篇 C语言简介
  7. 荣耀x10和荣耀30s哪个好?
  8. C# 实现海康摄像头在任意浏览器中预览
  9. Vue3应用API——use解析
  10. pointnet++代码逐行解析(一)——— train_classification