如何使用 React 在 Django 中创建和处理相关字段?

How to create and handle a related field in django with react?

我创建了 2 个模型 - 标签和初创公司。 Startups 有一个 tags 字段,与 Tag 有 ManytoMany 关系。

Models.py 文件 -

从django.db导入模型 来自 django_extensions.db.fields 导入 AutoSlugField 从 django.db.models 导入 CharField、TextField、DateField、EmailField、ManyToManyField

class Tag(models.Model):

    name = CharField(max_length=31, unique=True, default="tag-django")
    slug = AutoSlugField(max_length=31, unique=True, populate_from=["name"])

    def __str__(self):
        return self.name


class Startup(models.Model):

    name = CharField(max_length=31, db_index=True)
    slug = AutoSlugField(max_length=31, unique=True, populate_from=["name"])
    description = TextField()
    date_founded = DateField(auto_now_add=True)
    contact = EmailField()
    tags = ManyToManyField(Tag, related_name="tags")

    class Meta:
        get_latest_by = ["date_founded"]

    def __str__(self):
        return self.name

我的serializers.py文件-

from rest_framework.serializers import HyperlinkedModelSerializer, PrimaryKeyRelatedField, ModelSerializer
from .models import Startup, Tag


class TagSerializer(HyperlinkedModelSerializer):
    class Meta:
        model = Tag
        fields = "__all__"
        extra_kwargs = {
            "url": {
                "lookup_field": "slug",
                "view_name": "tag-api-detail"
            }
        }


class StartupSerializer(HyperlinkedModelSerializer):
    tags = TagSerializer(many=True, read_only=True)

    class Meta:
        model = Startup
        fields = "__all__"
        extra_kwargs = {
            "url": {
                "lookup_field": "slug",
                "view_name": "startup-api-detail"
            }
        }

我的viewsets.py文件-

from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from .serializers import TagSerializer, StartupSerializer
from .models import Tag, Startup
from rest_framework.decorators import action
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_200_OK, HTTP_204_NO_CONTENT
from django.shortcuts import get_object_or_404


class TagViewSet(ModelViewSet):

    queryset = Tag.objects.all()
    serializer_class = TagSerializer
    lookup_field = "slug"


class StartupViewSet(ModelViewSet):

    serializer_class = StartupSerializer
    queryset = Startup.objects.all()
    lookup_field = "slug"


    @action(detail=True, methods=["HEAD", "GET", "POST"], url_path="tags")
    def tags(self, request, slug=None):
        
        startup = self.get_object()
        print(startup)
        if request.method in ("HEAD", "GET"):
            s_tag = TagSerializer(
                startup.tags,
                many=True,
                context={"request": request}
            )
            return Response(s_tag.data)

        tag_slug = request.data.get("slug")
        if not tag_slug:
            return Response(
                "Slug of Tag must be specified",
                status=HTTP_400_BAD_REQUEST
            )
        tag = get_object_or_404(Tag, slug__iexact=tag_slug)
        startup.tags.add(tag)
        return Response(HTTP_204_NO_CONTENT)

我可以通过我的 django 管理员创建初创公司和关联标签。 我的 django 管理中有一个包含所有已创建标签的下拉列表,我可以从中将标签与初创公司相关联。

我不明白在反应中创建启动时如何将标签与启动相关联。 我尝试以这种形式发布数据 -

{
    "name": "Test Startup 1",
    "description": "First Desc",
    "contact": "first@gmail.com",
    "tags": [
        {
            "url": "http://127.0.0.1:8000/api/v1/tag/first-tag/",
            "name": "First Tag",
            "slug": "first-tag"
        }
    ]
}

我无法获取与启动相关的标签。

如何处理相关字段?

您有多种选择。

如果你想执行关联(意味着标签和启动在发出请求之前已经存在,有点像 django-admin 发生的事情),你可以创建一个新的序列化程序,它有一个不同的标签字段,接受 id而不是嵌套的序列化程序。

如果你想嵌套 creation/edition,你可以从 here. Because the doc says that it does not handle such usecase, because they might be many way to perform this depending on your business logic, but provide ways to perform that yourself here

查看 WritableNestedSerializer

另一种方法是使用嵌套资源(例如嵌套路由器)的路由,因此当您 POST 在 /startup/1/tags/ 中创建标签时,您会自动创建并关联您的标签,就像您一样做了。

现在,关于您的端点,您需要获取请求的数据并将其传递给标签序列化程序。此序列化程序随后将验证您的数据,如果有效,您可以执行标记创建。

为此,您可以执行以下操作:

tag_data = request.data
tag_serializer = TagSerializer(data=request.data)
tag_serializer.is_valid()
tag = tag_serializer.save()
tag.startup_set.add(startup)

添加关系必须分两步完成。您应该使用事务来确保它被正确创建。 此外,不要在您的视图中添加此逻辑,您应该覆盖 TagSerializer/StartupSerializer create 方法来执行此操作。