Как создать и обработать связанное поле в django с помощью react?

Я создал 2 модели -... Tags и Startups. Startups имеет поле tags с отношением ManytoMany с Tag.

Файл Models.py -

from django.db import models from django_extensions.db.fields import AutoSlugField from django.db.models import 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 admin, из которого я могу связать теги со стартапами.

Я не понимаю, как я могу связать теги со стартапом при создании стартапа в react. Я пробовал размещать данные в этой форме -

{
    "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"
        }
    ]
}

Я не могу добиться того, чтобы теги были связаны с запуском.

Как обрабатывать связанные поля?

У вас есть несколько вариантов.

Если вы хотите выполнить ассоциацию (то есть теги и startup уже существуют до выполнения запроса, как это происходит с django-admin), вы можете создать новый сериализатор, который будет иметь другое поле для тегов, принимая ids вместо вложенного сериализатора.

Если вы хотите иметь вложенное создание/изменение, вы можете воспользоваться WritableNestedSerializer из здесь. Поскольку в документации сказано, что он не обрабатывает такие случаи, потому что может быть много способов выполнить это в зависимости от вашей бизнес-логики, но предоставить способы выполнить это самостоятельно здесь

Другим подходом может быть маршрут с вложенными ресурсами (например, с вложенными маршрутизаторами), поэтому, когда вы размещаете тег в /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 для этого.

Вернуться на верх