我有以下的Django模型

class Component(models.Model):
    parent = models.ForeignKey(
        "self", on_delete=models.CASCADE, null=True, blank=True, related_name="children"
    )
    vessel = models.ForeignKey(
        Vessel, on_delete=models.CASCADE, related_name="components"
    )
    name = models.CharField(max_length=100)
    manufacturer = models.CharField(max_length=255, null=True, blank=True)
    model = models.CharField(max_length=255, null=True, blank=True)
    type = models.CharField(max_length=255, null=True, blank=True)
    serial_number = models.CharField(max_length=255, null=True, blank=True)
    supplier = models.CharField(max_length=255, null=True, blank=True)
    description = models.TextField(null=True, blank=True)
    image = models.ImageField(upload_to="component_images", blank=True, null=True)

    def __str__(self):
        return self.name

此视图集如下所示

class ComponentViewSet(viewsets.ModelViewSet):
    serializer_class = ComponentSerializer

    def get_queryset(self):
        queryset = Component.objects.all()
        vessel_id = self.kwargs.get("vessel_id", None)
        if vessel_id is not None:
            queryset = queryset.filter(vessel_id=vessel_id)
        queryset = queryset.filter(Q(parent=None) | Q(parent__isnull=True))
        return queryset

    def retrieve(self, request, pk=None, vessel_id=None):
        queryset = Component.objects.all()
        component = get_object_or_404(queryset, pk=pk, vessel_id=vessel_id)
        serializer = ComponentSerializer(component)
        return Response(serializer.data)

    def update(self, request, pk=None, vessel_id=None, partial=True):
        queryset = Component.objects.all()
        component = get_object_or_404(queryset, pk=pk, vessel_id=vessel_id)
        serializer = ComponentSerializer(component, data=request.data, partial=partial)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=["delete"])
    def delete_component(self, request, pk=None, vessel_id=None):
        queryset = Component.objects.all()
        component = get_object_or_404(queryset, pk=pk, vessel_id=vessel_id)

        # Recursively delete all children of the component
        self._delete_children(component)

        # Delete the component itself
        component.delete()

        return Response(status=status.HTTP_204_NO_CONTENT)

    def _delete_children(self, component):
        children = component.children.all()
        for child in children:
            self._delete_children(child)
            child.delete()

序列化程序:

class ImageSerializerField(serializers.Field):
    def to_representation(self, value):
        if not value:
            return None
        if settings.MEDIA_URL in value.url:
            return (
                settings.BASE_URL
                + settings.MEDIA_URL
                + value.url[len(settings.MEDIA_URL) :]
            )
        return value.url

    def to_internal_value(self, data):
        return data


class RecursiveField(serializers.Serializer):
    def to_representation(self, value):
        serializer = self.parent.parent.__class__(value, context=self.context)
        return serializer.data


class ComponentSerializer(serializers.ModelSerializer):
    children = RecursiveField(many=True)
    image = ImageSerializerField()

    class Meta:
        model = Component
        fields = "__all__"

这是我用来创建组件的简单react 表单

import React, { useState } from "react";
import { api } from "../../../../../userAuth/auth";
import { useParams } from "react-router";
const ComponentData = () => {
  const { vessel_id } = useParams();
  const [formData, setFormData] = useState({
    vessel: vessel_id,
    name: "",
    manufacturer: "",
    model: "",
    type: "",
    serial_number: "",
    supplier: "",
    description: "",
    image: null,
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData((prevFormData) => ({
      ...prevFormData,
      [name]: value,
    }));
  };

  const handleImageChange = (e) => {
    const file = e.target.files[0];
    setFormData((prevFormData) => ({
      ...prevFormData,
      image: file,
    }));
  };
  const handleSubmit = async (e) => {
    e.preventDefault();

    try {
      const { children, ...data } = formData; // Exclude the 'children' field

      const response = await api.post(
        `/maintenance/${vessel_id}/components/`,
        data
      );

      // TODO: Handle successful creation (e.g., show success message, redirect, etc.)
    } catch (error) {
      console.error("Error creating component:", error);
      // TODO: Handle error (e.g., show error message, etc.)
    }
  };
  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input
          type="text"
          name="name"
          value={formData.name}
          onChange={handleChange}
          required
        />
      </label>
      <br />
      <label>
        Manufacturer:
        <input
          type="text"
          name="manufacturer"
          value={formData.manufacturer}
          onChange={handleChange}
        />
      </label>
      <br />
      <label>
        Model:
        <input
          type="text"
          name="model"
          value={formData.model}
          onChange={handleChange}
        />
      </label>
      <br />
      <label>
        Type:
        <input
          type="text"
          name="type"
          value={formData.type}
          onChange={handleChange}
        />
      </label>
      <br />
      <label>
        Serial Number:
        <input
          type="text"
          name="serial_number"
          value={formData.serial_number}
          onChange={handleChange}
        />
      </label>
      <br />
      <label>
        Supplier:
        <input
          type="text"
          name="supplier"
          value={formData.supplier}
          onChange={handleChange}
        />
      </label>
      <br />
      <label>
        Description:
        <textarea
          name="description"
          value={formData.description}
          onChange={handleChange}
        />
      </label>
      <br />
      <label>
        Image:
        <input
          type="file"
          name="image"
          accept="image/*"
          onChange={handleImageChange}
        />
      </label>
      <br />
      <button type="submit">Create Component</button>
    </form>
  );
};

export default ComponentData;

每当我发送POST请求时,我都会收到错误的请求.当我判断里面的请求控制台时,会看到以下内容.

response
: 
config
: 
{transitional: {…}, adapter: Array(2), transformRequest: Array(1), transformResponse: Array(1), timeout: 0, …}
data
: 
children
: 
['This field is required.']
[[Prototype]]
: 
Object

我假设它谈论的是递归字段父级,但我已经在我的模型中声明了它不是必需的,所以我不确定我遗漏了什么.

推荐答案

主要问题是序列化程序,您的imagechildren字段没有指定它们是否是必需的,如果不是,默认情况下它们是必需的.对于children,如果我理解正确的话,它们将仅用于阅读,因此添加read_only=…以防止在RecursiveField中使用这些:

class ComponentSerializer(serializers.ModelSerializer):
    children = RecursiveField(many=True, read_only=True, required=False)
    image = ImageSerializerField(required=False)

    class Meta:
        model = Component
        fields = '__all__'

RecursiveField的实现也可能不适用于所有情况,例如没有many=True,这肯定会失败,因为parent没有parent.你可能想用django-rest-framework-recursive [GitHub],这是proxies most attributes [GitHub].

最后,串行化程序做了太多的way.你所做的大部分都是套话.例如,删除所有子对象和子对象等将由Django的ORM处理,并且以更高效的方式进行.通过这样做,您还使以后更难执行适当的身份验证、授权、限制等.ModelViewSet已经具有获取列表、特定项目等的样板逻辑.

class ComponentViewSet(viewsets.ModelViewSet):
    queryset = Component.objects.all()
    serializer_class = ComponentSerializer

    def get_queryset(self, *args, **kwargs):
        queryset = super().get_queryset(*args, **kwargs)
        vessel_id = self.kwargs.get('vessel_id')
        if vessel_id is not None:
            queryset = queryset.filter(vessel_id=vessel_id)
        return queryset.filter(parent=None)

这就是我们所需要的.

Reactjs相关问答推荐

LocalStore未存储正确的数据

Inbox Enum类型以React组件状态时出现TypScript错误

react 表复选框不对任何操作做出react

Next.js-图像组件加载问题

是否为Reaction中未使用的组件生成Tailwincss样式?

根据用户 Select 的注册类型更改表单字段

状态改变不会触发重新渲染

UseEffect 似乎不适用于页面的首次渲染

从 MongoDB createAt 字段中分割精确时间

通过createRoot创建的React元素无法调用Provider值

react 本机屏幕转换

面临 React 模式中点击外部条件的问题

如何更改TimePicker中下拉菜单的背景 colored颜色 和字体 colored颜色 - MUI React

useEffect内部的RETURN语句在首次按钮点击事件中似乎无效的原因是什么?

无法读取未定义的属性(阅读 'editQuoteModalShown')reactredux

如何让 useEffect 在 React.JS 中只运行一次?

使用 map 循环浏览列表列表中的列表并显示它们

如何保留我的下一个授权用户会话?所以我可以使用提供的 ID 在其他路由中获取数据

在 React 中将路径与查询变量匹配

React Router v6 - 访问嵌套路由和处理手写 url 的正确方法