Загрузка нескольких файловых объектов в API в виде массива файлов 2d

Я пытаюсь создать API с помощью django, который поддерживает загрузку файлов в виде массива массивов. Пример того, чего я пытаюсь достичь, следующий:

[
    {
        "string": "Some string",
        "files": [
            "<uploaded file object 1>",
            "<uploaded file object 2>"
        ]
    },
    {
        "string": "Some string",
        "files": [
            "<uploaded file object 3>"
        ]
    },
    {
        "string": "Some string",
        "files": []
    }
]

Я не хочу использовать для этого файлы в кодировке base64, так как файлы могут быть иногда большими, и я не хочу увеличивать накладные расходы, используя base64.

**Как я могу достичь этого вызова API наиболее эффективным способом, и какая структура будет наиболее подходящей для вызова этого API, и помогите с некоторым кодом javascript фронтенда для этого. **

Я попытался переместить это в FormData, где я могу достичь загрузки, как показано ниже, но я не могу вызвать API из фронтенда, это не работает, возможно, потому что я пишу неправильный код.

strings: ["Some string", "Some string", "Some string"]
files: [["<uploaded file object 1>", "<uploaded file object 2>"], ["<uploaded file object 3>"]]

Для бэкенда я использую django (rest framework), вот соответствующая часть сериализатора, если требуется

class StringSerializer(serializers.Serializer):
    serializers = serializers.ListField(child=serializers.CharField())
    files = serializers.ListField(
        child=serializers.ListField(child=serializers.FileField()),
        write_only=True,
        required=False,
        allow_empty=True,
        default=[],
    )

Примеры кодов с использованием FormData, Frontend и Backend (express)

Основные моменты кодирования фронтенда:

a. Для представления содержимого файла был создан объект blob. Обратитесь к утверждению: stmt-1.

b. Строка свойств была использована для установки ключа в объекте FormData.

c. Каждый объект blob в массиве был добавлен в formData по отдельности.

Для обоих вышеприведенных пунктов обратитесь к утверждению: stmt-2.

d. API был вызван внутри хука useEffect. Обратитесь к утверждению: stmt-3.

e. Статус загрузки был обновлен в переменной state. Обратитесь к утверждению: stmt-4.

App.js

import { useEffect, useState } from 'react';

export default function App() {
  const [uploadStatus, setUploadStatus] = useState('');

  const someContent = '<q id="a"><span id="b">hey!</span></q>';
  const blob = new Blob([someContent], { type: 'text/xml' }); // stmt 1
  const data = [
    {
      string: 'Somestring1',
      files: [blob, blob],
    },
    {
      string: 'Somestring2',
      files: [blob],
    },
    {
      string: 'Somestring3',
      files: [blob],
    },
  ];

  const formData = new FormData();
  data.forEach((rec) => {
    rec.files.forEach((file) => {
      formData.append(rec.string, file); // stmt-2
    });
  });

  useEffect(() => {
    fetch('http://localhost:3001/api/upload', {
      method: 'POST',
      body: formData,
    })
      .then((response) => response.text())
      .then((data) => setUploadStatus(data)); // stmt-4
  }, []); // stmt-3

  return 'Upload Status : ' + (uploadStatus ? uploadStatus : 'Unknown');
}

Бэкенд - Express с использованием multer middleware

Основные моменты кодирования

a. Код multipart-formdata во фронтенде был получен nodejs middleware multer. Подробнее о multer, смотрите на странице https://www.npmjs.com/package/multer.

server.js

const express = require('express');
const multer = require('multer');
const cors = require('cors');
const upload = multer({
  dest: 'uploads',
});

const app = express();
app.use(cors());

app.post('/api/upload', upload.any(), (req, res, next) => {
  console.log(req.files);
  res.send('success');
});

app.listen(3001, () => {
  console.log('Listening...');
});

Пробный запуск:

При выполнении кода фронтенда файлы будут загружены автоматически, а на внутреннем сервере будут созданы журналы консоли сервера, как показано ниже.

[
  {
    fieldname: 'Somestring1',
    originalname: 'blob',
    encoding: '7bit',
    mimetype: 'text/xml',
    destination: 'uploads',
    filename: 'f94460f91f497bac0c1e0fdc4292eadc',
    path: 'uploads/f94460f91f497bac0c1e0fdc4292eadc',
    size: 38
  },
  {
    fieldname: 'Somestring1',
    originalname: 'blob',
    encoding: '7bit',
    mimetype: 'text/xml',
    destination: 'uploads',
    filename: 'deb237a854b4027a9e106effc236343d',
    path: 'uploads/deb237a854b4027a9e106effc236343d',
    size: 38
  },
  {
    fieldname: 'Somestring2',
    originalname: 'blob',
    encoding: '7bit',
    mimetype: 'text/xml',
    destination: 'uploads',
    filename: '52fd4e96f278f216f339be0f72ce1b6f',
    path: 'uploads/52fd4e96f278f216f339be0f72ce1b6f',
    size: 38
  },
  {
    fieldname: 'Somestring3',
    originalname: 'blob',
    encoding: '7bit',
    mimetype: 'text/xml',
    destination: 'uploads',
    filename: '781e6d3bbf3fb01149fa7fd8e428339d',
    path: 'uploads/781e6d3bbf3fb01149fa7fd8e428339d',
    size: 38
  }
]

В папке uploads в бэкенде будут храниться загруженные файлы. Их список приведен ниже.

Uploads folder with files

Вернуться на верх