Как обновить поле "многие ко многим" в DRF

В моем проекте есть модель пользователя и модель школы. Моя модель пользователя имеет поле schools, которое имеет M2M отношение с моделью школы. Теперь я хочу знать, как я могу создать представление, которое может взять email пользователя и Id школы, и добавить школу или удалить ее из школ, к которым принадлежит user.

Вот мой user model:

class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=255, unique=True, db_index=True)
    email = models.EmailField(max_length=255, unique=True, db_index=True)
    is_verified = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now_add=True)
    schools = models.ManyToManyField("School", related_name="members")

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    objects = UserManager()

    def __str__(self):
        return self.email

    def tokens(self):
        refresh = RefreshToken.for_user(self)
        return {
            'refresh': str(refresh),
            'access': str(refresh.access_token)
        }
<
class School(models.Model):
    name = models.CharField(max_length=300, verbose_name='school name', )
    principal = models.ForeignKey("User", related_name="my_schools", on_delete=CASCADE)
    address = models.CharField(max_length=200)

    class Type(models.IntegerChoices):
        PUBLIC = 1, "Public"
        PRIVATE = 2, "Private"

    type = models.PositiveSmallIntegerField(choices=Type.choices, default=Type.PUBLIC)

    class Level(models.IntegerChoices):
        NATIONAL = 1, "National"
        EXTRACOUNTY = 2, "Extra County"
        COUNTY = 3, "County"
        SUBCOUNTY = 4, "Subcounty"

    level = models.PositiveSmallIntegerField(choices=Level.choices, default=Level.COUNTY)

    def __str__(self):
        return self.name

Вот сериализатор для регистрации членов:

class EnrollSchoolMembersSerializer():
    class Meta:
        model = User
        field = ('email')

Я думаю, что вы можете реализовать это, используя представление API функций. Во-первых, вы можете определить сериализатор.

from rest_framework import serializers as sz

class SchoolUpdateSerializer(sz.Serializer):
    school_id = sz.IntegerField()
    email = sz.EmailField()
    mode = sz.CharField()      # can be either 'add' or 'delete'

А в файле views.py можно написать обработчик.

from rest_framework.response import Response
from rest_framework status
from rest_framework.decorators import api_view, permission_classes
from .models import School, User
from .serializers import SchoolUpdateSerializer

@api_view(['POST'])
@permission_classes([permissions.AllowAny])
def update_school_data(request):
    serializer = SchoolUpdateSerializer(data = request.data)
    if serializer.is_valid()
        input_data = serializer.validated_data
        email = input_data.get('email')
        mode = input_data.get('mode')
        school_id = input_data.get('school_id')
        try:
            user = User.objects.get(email = email)
            school = School.objects.get(pk = school_id)
            if mode == "add":
                user.schools.add(school)
            else:
                user.schools.remove(school)
            return Response(status = status.HTTP_200_OK)       
        except (User.DoesNotExist, School.DoesNotExist):
            return Response(status = status.HTTP_400_BAD_REQUEST)
    else:
        return Response(status = status.HTTP_400_BAD_REQUEST)
        

Наконец, во фронтенде вы можете использовать POST API. Полезная нагрузка может быть

{
    "email": "test@example.com",
    "school_id": 1,
    "mode": "add"
}

Смотрите документацию по REST-фреймворку Django на https://www.django-rest-framework.org/api-guide/serializers/#writing-update-methods-for-nested-representations

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