You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django/React食谱项目Ingredients数组添加失败及提交报错排查

排查RecipeForm的食材数组问题 & 提交错误

咱们一步步来解决你遇到的问题,你收到的"ingredients: ["This field is required."]"错误,本质是食材数组没有正确更新,也没有正确传递给后端。下面是核心问题的修复方案:

1. 修复handleAddIngredients的state更新逻辑

你当前的代码在添加新食材时犯了两个错误:错误的解构语法和直接修改原state数组(React无法检测到这种修改)。

原错误代码:

handleAddIngredients =(e) => {
  e.preventDefault();
  let ingredient = {units: '', amounts: '', multiples: '', quantity: '', name: ''};
  let {ingredients} = this.state.ingredients; // 这里解构错误
  ingredients.push(ingredient); // 直接修改原state数组
  this.setState( {ingredients: ingredients});
};

修复后的代码:

handleAddIngredients = (e) => {
  e.preventDefault();
  // 创建新的空食材对象
  const newIngredient = {units: '', amounts: '', multiples: '', quantity: '', name: ''};
  // 使用函数式setState,基于最新state创建新数组(避免直接修改原state)
  this.setState(prevState => ({
    ingredients: [...prevState.ingredients, newIngredient]
  }));
};

这样做的好处是:

  • 用扩展运算符...复制原数组,生成新数组,不会修改原state
  • 函数式setState确保拿到的是最新的state值,避免异步更新导致的错误

2. 修复食材输入框的状态绑定

现在你的食材输入框没有正确绑定到数组中对应的对象,handleIngredientInput只是把值存在state的根节点,而不是对应索引的食材对象里。

第一步:修改handleIngredientInput,支持索引定位

handleIngredientInput = (index, e) => {
  e.preventDefault();
  const { name, value } = e.target;
  this.setState(prevState => {
    // 复制原食材数组
    const updatedIngredients = [...prevState.ingredients];
    // 更新对应索引的食材对象(保留其他属性,只修改当前输入的字段)
    updatedIngredients[index] = {
      ...updatedIngredients[index],
      [name]: value
    };
    return { ingredients: updatedIngredients };
  });
};

第二步:修正render中的输入框绑定

原来的map循环里,value绑定的是this.state.ingredients.quantity(这是数组的属性,根本不存在),应该绑定当前循环的ingredient对象的属性,同时在onChange时传递当前索引:

{this.state.ingredients.map((ingredient, index) => {
  return (
    <div key={index}>
      <Form.Control 
        type="number" 
        placeholder="#" 
        id={`numberAmount-${index}`}
        value={ingredient.quantity} 
        onChange={(e) => this.handleIngredientInput(index, e)} 
        name="quantity" // 注意:要和state里的字段名一致
      />
      <Form.Control 
        type="text" 
        placeholder="units" 
        id={`units-${index}`}
        value={ingredient.units} 
        onChange={(e) => this.handleIngredientInput(index, e)} 
        name="units"
      />
      <Form.Control 
        type="text" 
        placeholder="Ingredient Name" 
        id={`name-${index}`}
        value={ingredient.name} 
        onChange={(e) => this.handleIngredientInput(index, e)} 
        name="name"
      />
      {/* 注意:你state里的字段是amounts,这里如果输入框对应这个字段,name要改成amounts */}
    </div>
  );
})}

另外,你之前的servings输入框绑定错误,应该改成:

<Form.Control 
  type="number" 
  placeholder="servings" 
  id="servings" 
  value={this.state.servings} // 这里是state根属性,不是ingredients里的
  onChange={this.handleInput} 
  name="servings" 
/>

3. 修复FormData传递数组的问题

Django DRF无法直接接收FormData中的数组对象,因为FormData只能处理字符串或二进制数据。你需要把食材数组转成JSON字符串再传递:

修改submitRecipe中的这一行:

// 原代码:formData.append("ingredients", this.state.ingredients);
formData.append("ingredients", JSON.stringify(this.state.ingredients));

然后在Django后端,需要解析这个JSON字符串:

后端视图处理示例

import json
from rest_framework.views import APIView

class RecipeCreateView(APIView):
    def post(self, request, *args, **kwargs):
        # 解析JSON格式的ingredients
        ingredients_json = request.data.get('ingredients')
        if ingredients_json:
            ingredients = json.loads(ingredients_json)
            request.data['ingredients'] = ingredients
        # 后续交给序列化器处理
        serializer = RecipeSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)

序列化器配置

确保你的序列化器中ingredients字段是ListField类型:

from rest_framework import serializers
from .models import Recipe

class RecipeSerializer(serializers.ModelSerializer):
    ingredients = serializers.ListField(child=serializers.DictField())
    # 其他字段配置...
    class Meta:
        model = Recipe
        fields = ['title', 'creator', 'mealTime', 'prepTime', 'cookTime', 'servings', 'directions', 'ingredients', 'image']

4. 其他小问题修复

  • mealTime下拉框没有绑定state,需要添加name和onChange:
<Form.Control 
  as="select" 
  name="mealTime"
  value={this.state.mealTime}
  onChange={this.handleInput}
>
  <option>Breakfast</option>
  <option>Lunch</option>
  <option>Dinner</option>
  <option>Dessert</option>
  <option>Vegetarian</option>
</Form.Control>
  • 温度选择框如果需要提交,也需要类似的绑定处理。

做完这些修改后,你的食材数组应该能正确更新,提交时也能把食材数据正确传递给后端,解决"This field is required."的错误。

内容的提问来源于stack exchange,提问作者Christina Roberts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 06:31:23