Skip to content

分块上传

后端程序员在面临大文件要通过前端Vue 或者React 分片上传的时候,后端Django Rest Framework如何处理呢?

Django Rest Framework的灵活的方法处理大文件上传

即使大文件在前端使用Vue.js或者React.js进行了分割成块也是如此。以下是如何设计序列化器来处理这种情况的总体概述:

  1. 使用选项定义文件字段chunks_size:

    在序列化器类中,定义aFileField并将chunks_size选项设置为每个块的适当大小。此选项指定序列化器将接受的每个块的最大大小。

    python
    import shutil
    from rest_framework import serializers
    class MyFileSerializer(serializers.ModelSerializer):
      file = serializers.FileField(chunks_size=1024*1024) # 1MB chuncks
  2. 在方法中处理块:

    重写序列化器的save()方法来处理传入的文件块。每个块上传时都会重复调用此方法。

    python
    def save(self, **kwargs):
      request = self.context["request"]
      file = request.FILES["file"]
      if "file_complete" in request.data:
        self.process_complete_file(file)
      else:
        self.process_chunk(file)
  3. 实施process_chunk()process_complete_file():

    创建这些方法来分别处理单个块和整个文件的逻辑

    python
    def process_chunk(self, file):
      chunk_data = file.read()
      temp_file = tempfile.NamedTemporaryFile()
      temp_file.write(chunk_data)
      temp_file.seek(0)
      chunk_data= temp_file.read().decode("utf-8")
      temp_file.close()
     
    
    def process_complete_file(self, file):
      chunks = []
      temp_dir = tempfile.mkdtemp()
      
      for chunk_num in range(1, self.get_total_chunks() +1):
        chunk_file_path = os.path.join(temp_dir, f'chunk_{chunk_num}')
        with open(chunk_file_path, 'rb') as chunk_file:
          chunks.append(chunk_file.read())
      complete_file_data = b"".join(chunks)
      
      file_path = os.path.join(settings.MEDIA_ROOT, file.name)
      with open(file_path, "wb") as complete_file:
        complete_file.write(complete_file_data)
       
     	shutil.rmtree(temp_dir)
  4. 用于块上传的前端Vue.js代码

    Vue.js前端代码中,使用axios Fetch API 等库来分块上传文件。在每个请求中设置Content-Range表头以指示块大小和位置。

    javascript
    const uploadFile = (file) => {
      const chunkSize = 1024*1024;
      let start = 0;
      let end = chunkSize;
      let totalChunks = Math.ceil(file.size / chunkSize);
      
      const formData = new FormData();
      formData.append("file", file);
      
      while (start < file.size){
        const chunk = file.slice(start, end);
        formData.append("chunk", chunk);
        
        const headers = {
          "Content-Range": `bytes ${start}-${end-1} / ${file.size}`
        };
        axios.post("/api/upload/", formData, {headers}).then(() => {
          start = end;
          end = Math.min(end + chunkSize, file.size);
          if(end === file.size){
            formData.append("file_complete", true);
            axios.post("/api/upload/", formData, {headers});
          }
        })
        .catch(error => {
          console.log("Error uploading chunk", error);
        })
      }
    }

    这种方法允许程序员将大文件上传分解为可管理等块,从而减少内存占用并提高上传性能,从而有效地处理大文件上传。序列化器save()方法负责管理块,单独处理它们,并最终组装完整的文件。

Released under the MIT License.