文件上传
一、概要
文件上传与下载也是开发中的比较重要的功能
二、前期配置文件
- 在settings文件中
MEDIA_ROOT = BASE_DIR + ‘/media/’
BASE_DIR 是项目所在的目录,这样文件就会存储在当前的开发目录下的一个media的文件夹下
MEDIA_URL = ‘/media/’ - 在整个项目中添加的url.py中
urlpatterns = [
url(r’^admin/’, admin.site.urls),
] + static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
#官方给出的在开发中显示图片的方式,但是只能用于本地开发的时候,也就是127.0.0.1的时候。而不能用在发布版
三、相关类
1、说明
- 表单上传的文件对象存储在类字典对象request.FILES中,表单格式需为multipart/form-data
- request.FILES中的键来自于表单中的的name值:
- request.FILES中的值均为UploadedFile类文件对象。
2、request.FILES
- 说明
一个类字典对象,包含所有上传的文件。 FILES 的键来自 中的 name。 FILES 的值是一个标准的Python字典 - 示例代码
# 返回 uploadfile对象 key对应的是input对象的name的值, 默认是file
upload_file =request.FILES[‘file’]
#或者
upload_file =request.FILES.get(‘file’) - 返回值
QueryDict对象 - 注意
FILES 只在请求的方法是 POST,并且提交的 包含enctype="multipart/form-data"时才包含数据。否则, FILES 只是一个空的类字典对象。
3、UploadedFile
- 说明
是类文件对象 - 方法
- UploadedFile.read()
读取整个上传文件的数据,文件较大时慎用。 - UploadedFile.multiple_chunks(chunk_size=None)
判断文件是否足够大,一般为设置2.5M - UploadedFile.multiple_chunks(chunk_size=None)
返回一个生成器对象,当multiple_chunks()为True时应该使用这个方法来代替read() - UploadedFile.chunks(chunk_size=None)
返回一个生成器对象指定切割文件大小 - UploadedFile.name
上传文件的name。 - UploadedFile.size
上传文件的大小 - UploadedFile.content_type
上传文件时的content_type报头,例如(image/* , application/pdf). - UpladedFile.charset
获取上传文件的编码
- UploadedFile.read()
四、文件上传
1、说明
表单上传的文件对象存储在类字典对象request.FILES中,表单格式需为multipart/form-data
2、示例代码
-
前端
<form enctype="multipart/form-data" method="post" action="/upload"> <input type="file" name="head" /> </form>
-
views
def upload(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') user = UserInfo() user.head = request.FILES.get('head') user.username = username user.password = password user.save() return render(request, 'index.html')
-
models
class UserInfo(models.Model): uid = models.AutoField(primary_key=True) username = models.CharField(max_length=32, unique=True) password = models.CharField(max_length=32) # "直接定位到media目录下" # head = models.FileField(upload_to='account/user/%Y%m%d') class Meta: db_table = 'T_USER_INFO'
-
如果需要给文件重名了,定义一个类继承FileSystemStorage 重新_save()方法
from django.core.files.storage import FileSystemStorage
class CustomFileStorage(FileSystemStorage): from django.conf import settings def __init__(self, location=settings.MEDIA_ROOT, base_url=settings.MEDIA_URL): # 初始化 super(ImageStorage, self).__init__(location, base_url) # 重写 _save方法 def _save(self, name, content): # name为上传文件名称 import os, time, random # 文件扩展名 ext = os.path.splitext(name)[1] # 文件目录 d = os.path.dirname(name) # 定义文件名,年月日时分秒随机数 fn = time.strftime('%Y%m%d%H%M%S') fn = 'IMG_' + fn + '%d' % random.randint(0, 100) # 重写合成文件名 name = os.path.join(d, fn + ext) # 调用父类方法 return super()._save(name, content) #在models中添加 # 如果上传文件可以将ImageField换为FileField pic=models.ImageField(upload_to='img/%Y/%m/%d',storage=CustomFileStorage())
五、自带的Form来处理上传文件
-
定义models
class UserInfo(models.Model): uid = models.AutoField(primary_key=True) username = models.CharField(max_length=32, unique=True) password = models.CharField(max_length=32) # "直接定位到media目录下" # head = models.FileField(upload_to='account/user/%Y%m%d') class Meta: db_table = 'T_USER_INFO'
-
定义FileFiled或者ImageFiled的Form
class UploadFileForm(forms.Form): title = forms.CharField(max_length=50) file = forms.FileField()
-
views
def make_file_name(upload_file_name): """ 自定义文件名 """ import time, random # 文件扩展名 upload_file_name.rfind([pload_file_name.rfind('.')]:) # 定义文件名,年月日时分秒随机数 fn = time.strftime('%Y%m%d%H%M%S') fn = 'IMG_' + fn + '%s' % random.randint(0, 100) return fn def save_uploaded_file(uploadFile): """ 保存文件 """ with open(get_file_name(uploadFile.name), 'wb') as file: for chunk in uploadFile.chunks(): file.write(chunk) def upload_file(request): if request.method == 'POST': form = UploadFileForm(request.POST, request.FILES) # 判断是否第一次请求 if form.is_valid(): save_uploaded_file(request.FILES['file']) return render(request,'success.html') else: form = UploadFileForm() return render('upload.html', {'form': form})
-
前端upload.html
<form action="/upload/" method="post"> {% csrf_token %} {{ form }} <input type="submit" value="上传" /> </form>
六、ajax上传
-
models
class UserInfo(models.Model): uid = models.AutoField(primary_key=True) username = models.CharField(max_length=32, unique=True) password = models.CharField(max_length=32) # "直接定位到media目录下" head = models.FileField(upload_to='account/user/%Y%m%d',storage=CustomFileStorage()) class Meta: db_table = 'T_USER_INFO'
-
views
def upload(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') user = UserInfo() user.head = request.FILES.get('head') user.username = username user.password = password user.save() return render(request, 'index.html')
-
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script language="JavaScript"> let register_url = 'http://127.0.0.1:8000/day06/register/'; $(function () { $("#register_btn").click(function () { let formdata = new FormData(); let fileobj = $('#head')[0].files[0]; let username = $('#username').val(); let password = $('#password').val(); formdata.append('username', username); formdata.append('password', password); formdata.append('head', fileobj); $.ajax(register_url, { type: 'POST', data: formdata, contentType: false, /*告诉jquery不要处理数据*/ processData: false, cache: false }) ; return false }); }) </script> </head> <body> <form id="register" action="/day06/register/" method="post" enctype="multipart/form-data"> <input type="text" id="username"> <input type="password" id="password"> <input type="file" id="head"> <input type="button" id="register_btn" value="注册"> <input type="reset" value="重置"> </form> </body> </html>