React中如何在FormData追加列表与文本?Django校验报错求助
问题:React FormData传递列表+文本数据时Django提示product_image必填错误
问题现象
提交请求后收到错误:product_image["This field is required."],明明已在FormData中添加product_image列表,但后端接收到的是JSON字符串,无法被Django序列化器识别。
后端Django要求的数据格式(仅接受此结构)
{ "Name": "1", "category": "1", "Description": "1", "archive": "true", "Banner": {}, "product_image": [ { "Name": "img[0]", "image": {}, "secret_key": "Keys" }, { "Name": "img[1]", "image": {}, "secret_key": "Keys" } ] }
注:{}代表文件对象
前端定义的数据
const p_details = { "Name": "1", "category": 1, "Description": "1", "archive": true, "Banner": {} } const p_img = { "Name": "img", "Image": { "0": {}, "1": {} } }
注:{}代表文件对象
现有前端React提交代码
const handleSubmit = async (event) => { event.preventDefault(); const products = new FormData(); Object.keys(p_details).forEach((key) => products.append(key, p_details[key])); // Iterate over the Image object and append each file var parentObj = []; for (var key in p_imgs.Image) { if (p_imgs.Image.hasOwnProperty(key)) { var file = p_imgs.Image[key]; var nameWithKey = p_imgs.Name + "[" + key + "]"; var obj = { "Name": nameWithKey, "user": 2, "image": file, "secret_key": "Keys" }; parentObj.push(obj); } } products.append('product_image', JSON.stringify(parentObj)); try { const response = await fetch('http://127.0.0.1:8000/media/product/create/', { method: 'POST', body: products }); if (!response.ok) { const errorMessage = await response.text(); throw new Error(`Server error: ${response.status} - ${errorMessage}`); } console.log('File uploaded successfully.', response); } catch (error) { console.error('Error uploading file:', error); console.error('Error uploading file:', error.response?.data); } };
后端Django Serializer代码
class ProductSerializer(serializers.ModelSerializer): product_image = ProductImageSerializer(many=True) class Meta: model = ProductSize fields = "__all__"
解决方案
问题根源
将product_image数组序列化为JSON字符串后append到FormData,Django的嵌套序列化器(带many=True)无法解析字符串格式的列表,且列表中包含文件对象,不能通过JSON传递。
修正后的前端代码
采用Django REST Framework支持的FormData嵌套列表命名规则,将每个product_image对象的字段单独append,格式为product_image[index].field_name:
const handleSubmit = async (event) => { event.preventDefault(); const products = new FormData(); // 处理基础字段 Object.keys(p_details).forEach((key) => { // 布尔值转字符串,避免FormData自动转换问题 const value = typeof p_details[key] === 'boolean' ? p_details[key].toString() : p_details[key]; products.append(key, value); }); // 处理product_image列表 let imgIndex = 0; for (const key in p_imgs.Image) { if (p_imgs.Image.hasOwnProperty(key)) { const file = p_imgs.Image[key]; const nameWithKey = `${p_imgs.Name}[${key}]`; // 按嵌套列表规则逐个append字段 products.append(`product_image[${imgIndex}].Name`, nameWithKey); products.append(`product_image[${imgIndex}].user`, 2); products.append(`product_image[${imgIndex}].image`, file); products.append(`product_image[${imgIndex}].secret_key`, "Keys"); imgIndex++; } } try { const response = await fetch('http://127.0.0.1:8000/media/product/create/', { method: 'POST', body: products }); if (!response.ok) { const errorMessage = await response.text(); throw new Error(`Server error: ${response.status} - ${errorMessage}`); } console.log('File uploaded successfully.', response); } catch (error) { console.error('Error uploading file:', error); console.error('Error uploading file:', error.response?.data); } };
说明
- 这种命名方式是DRF处理FormData中嵌套对象列表的标准格式,序列化器会自动将这些字段组合为对应的对象数组。
- 文件对象直接通过FormData传递,无需序列化,保证后端能正确解析文件流。
- 布尔值手动转为字符串,避免FormData将
true/false转为"true"/"false"时可能出现的解析问题(Django通常能自动处理,但显式转换更稳妥)。
内容的提问来源于stack exchange,提问作者K Kumar
相关产品推荐
相关产品推荐

