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

React RTK Query提交表单至DRF时提示必填字段错误

问题:React + RTK Query 向 Django Rest Framework POST 数据时返回字段必填错误

问题详情

尝试通过React结合RTK Query向Django Rest Framework后端提交POST请求,控制台显示表单所有字段已填充,但后端始终返回"This field is required."错误。

代码实现

CreateCampaign.js

import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";

import { money } from "../data";
import { CustomButton, FormField, Loader } from "../components";
import { useCreateCampaignMutation } from "../utils/userAuthApi";
import { getToken } from "../utils/index";

const CreateCampaign = () => {
  const navigate = useNavigate();
  const { access_token } = getToken();
  const [createCampaign, { isLoading }] = useCreateCampaignMutation();
  const [form, setForm] = useState({
    title: "",
    description: "",
    target: "",
    deadline: "",
  });

  const handleFormFieldChange = (fieldName, e) => {
    setForm({ ...form, [fieldName]: e.target.value });
    console.log(form);
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    console.log({ form, access_token });
    const res = await createCampaign({ form, access_token });
    if (res.data) {
      console.log(res.data);
    } else {
      console.log(res.error.data.errors);
    }
  };

  return (
    <div className="bg-[#1c1c24] flex justify-center items-center flex-col rounded-[10px] sm:p-10 p-4">
      {isLoading && <Loader />}
      <div className="flex justify-center items-center p-[16px] sm:min-w-[380px] bg-[#3a3a43] rounded-[10px]">
        <h1 className="font-epilogue font-bold sm:text-[25px] text-[18px] leading-[38px] text-white">
          Start a Campaign
        </h1>
      </div>

      <form
        onSubmit={handleSubmit}
        className="w-full mt-[65px] flex flex-col gap-[30px]"
      >
        <div className="flex flex-wrap gap-[40px]">
          {/* <FormField
            labelName="Your Name *"
            placeholder="John Doe"
            inputType="text"
            value={form.owner}
            handleChange={(e) => handleFormFieldChange("owner", e)}
          /> */}
          <FormField
            labelName="Campaign Title *"
            placeholder="Write a title"
            inputType="text"
            value={form.title}
            handleChange={(e) => handleFormFieldChange("title", e)}
          />
        </div>

        <FormField
          labelName="Story *"
          placeholder="Write your story"
          isTextArea
          value={form.description}
          handleChange={(e) => handleFormFieldChange("description", e)}
        />

        <div className="w-full flex justify-start items-center p-4 bg-[#8c6dfd] h-[120px] rounded-[10px]">
          <img
            src={money}
            alt="money"
            className="w-[40px] h-[40px] object-contain"
          />
          <h4 className="font-epilogue font-bold text-[25px] text-white ml-[20px]">
            You will get 100% of the raised amount
          </h4>
        </div>

        <div className="flex flex-wrap gap-[40px]">
          <FormField
            labelName="Goal *"
            placeholder="ETH 0.50"
            inputType="text"
            value={form.target}
            handleChange={(e) => handleFormFieldChange("target", e)}
          />
          <FormField
            labelName="End Date *"
            placeholder="End Date"
            inputType="date"
            value={form.deadline}
            handleChange={(e) => handleFormFieldChange("deadline", e)}
          />
        </div>

        <div className="flex justify-center items-center mt-[40px]">
          <CustomButton
            btnType="submit"
            title="Submit new campaign"
            styles="bg-[#1dc071]"
          />
        </div>
      </form>
    </div>
  );
};

export default CreateCampaign;

userAuthApi.js

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'

// Define a service using a base URL and expected endpoints
export const userAuthApi = createApi({
  reducerPath: 'userAuthApi',
  baseQuery: fetchBaseQuery({ baseUrl: 'http://127.0.0.1:8000/'}),
  endpoints: (builder) => ({
      createCampaign: builder.mutation({
      query: ({ campaignData, access_token }) => {
        return {
          url: 'campaigns/create/',
          method: 'POST',
          body: campaignData,
          headers: {
            'authorization': `Bearer ${access_token}`,
          }
        }
      }
    }),
  })
 })

服务器返回错误

{"title":["This field is required."],"description":["This field is required."]}

解决方案

核心问题

RTK Query的createCampaign mutation定义时接收的参数是{ campaignData, access_token },但实际调用时传递的是{ form, access_token },参数名称不匹配导致后端无法正确解析到title、description等字段,因此返回必填错误。

修复方式(二选一)

  1. 修改调用时的参数名:在handleSubmit方法中,将form重命名为campaignData:
const res = await createCampaign({ campaignData: form, access_token });
  1. 修改mutation的参数定义:将campaignData改为form,保持和调用时一致:
createCampaign: builder.mutation({
  query: ({ form, access_token }) => {
    return {
      url: 'campaigns/create/',
      method: 'POST',
      body: form,
      headers: {
        'authorization': `Bearer ${access_token}`,
      }
    }
  }
}),

额外检查点

  • 确认Django Rest Framework的序列化器中,title、description等字段名称与前端传递的完全一致,无拼写错误;
  • 可通过浏览器开发者工具的Network标签,查看POST请求的Payload或Form Data,确认发送的数据结构是否符合后端要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 20:19:52