python上传文件进度_Django Ajax 文件上传及进度显示

在Django 1.0 版本后,文件上传的处理做了很大的改变,其中很重要的一点就是引入了 Upload Handlers 的概念。Upload Handlers这是个和Django中的Middleware差不多的东西,可以通过在 settings.py 文件中设置 FILE_UPLOAD_HANDLERS 定义一系列Upload Handlers,和Middleware相似的地方主要表现为以下两...
摘要由CSDN通过智能技术生成

在Django 1.0 版本后,文件上传的处理做了很大的改变,其中很重要的一点就是引入了 Upload Handlers 的概念。

Upload Handlers

这是个和Django中的Middleware差不多的东西,可以通过在 settings.py 文件中设置 FILE_UPLOAD_HANDLERS  定义一系列Upload Handlers,

和Middleware相似的地方主要表现为以下两点:

1、Django会按照 FILE_UPLOAD_HANDLERS 所定义的列表中各个Upload Handlers的先后顺序将上传的文件数据依次传递给Upload Handlers。

2、Upload Handlers是一个类,可以通过定义各种hook methods,在文件上传的各个阶段进行相应操作。同时可以通过返回操作后的数据或只返回None等形式,对是否需要后续的Upload Handlers进行处理进行控制。

通过以上两点,Django本身内置了2个Upload Handlers:

("django.core.files.uploadhandler.MemoryFileUploadHandler",

"django.core.files.uploadhandler.TemporaryFileUploadHandler",)

第一个Handler是将上传的文件数据保存在内存中,如果上传的文件数据大小超过 FILE_UPLOAD_MAX_MEMORY_SIZE 所设置的值后,那么他只要将数据丢给后续的Handler(即TemporaryFileUploadHandler)即可。

通过此种处理方式,可以对文件上传进行详细的控制并进行各种有趣的操作,比如边上传边压缩,上传进度提示等。

而这次我所要讲的Ajax上传,进度显示就是通过自定义Handler实现的。通过定义以下的Handler,并且将该Handler放置在所有其他Handler之前,就可以在文件上传的过程中记录某个文件表单域所对应的上传进度。

from django.core.files.uploadhandler import FileUploadHandler

from django.core.cache import cache

import time

class LogFileUploadHandler(FileUploadHandler):

def __init__(self, request=None):

super(LogFileUploadHandler, self).__init__(request)

if 'formhash' in self.request.GET:

self.formhash = self.request.GET['formhash']

cache.add(self.formhash, {})

self.activated =True

else:

self.activated = False

def new_file(self, *args, **kwargs):

super(LogFileUploadHandler, self).new_file(*args, **kwargs)

if self.activated:

fields = cache.get(self.formhash)

fields[self.field_name] = 0

cache.set(self.formhash, fields)

def receive_data_chunk(self, raw_data, start):

# time.sleep(5) for local test, it slow down the upload speed

if self.activated:

fields = cache.get(self.formhash)

fields[self.field_name] = start

cache.set(self.formhash, fields)

return raw_data

def file_complete(self, file_size):

if self.activated:

fields = cache.get(self.formhash)

fields[self.field_name] = -1

cache.set(self.formhash, fields)

def upload_complete(self):

if self.activated:

fields = cache.get(self.formhash)

fields[self.formhash] = -1

cache.set(self.formhash, fields)

因为显示给每个用户每次浏览页面的时候,表单域的name都是相同的,为了区分每个页面,在表单提交的时候需要加上一个

formhash 的GET参数,以此来区分文件上传来源。

第一个问题,为什么formhash是一个GET参数,而不是POST参数,如果是POST的话不是更方便?因为只要在表单中加入一个hidden域即可。

那是因为如果在Handler尝试存取request.POST中的值,会导致又一次调用Upload Handler,从而形成无限递归,所以只能存取request.GET中的值。当然这并不是什么大问题,后面我会讲到用js将hidden域中的formhash提取出来作为GET参数。

第二个问题是如何保存文件上传进度的数据,用数据库来保存显然是开销太大了,因为一次文件上传的过程中需要反复读写记录的数据。最终我这里选择使用了django的cache组件来进行保存,因为保存的数据格式相对比较简单,并且对速度的要求比较高。(相关文章:http://www.djangosnippets.org/snippets/678/      http://www.djangosnippets.org/snippets/679/)

第三个问题,经实践测试,upload handler中的self.content_length 似乎一直都为None,所以在文件没有完整上传之前是没法获得总的数据长度的。因此此handler只记录了已上传的字节数,并且以 -1 表示上传结束。同样,为了表示一个表单中的所有文件上传域的文件上传完毕,通过将 formhash 作为key,值为 -1 来表示。

声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。更多精彩内容,访问http://jinhao.iteye.com/

如何提交表单

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值