Я пытаюсь опубликовать в поле отношений manytomany через модель, в которой вложена модель с отношением manytomany

#python-3.x #django #django-models #django-serializer #manytomanyfield

Вопрос:

Когда я пытаюсь опубликовать с помощью get_or_create и доступных для записи вложенных сериализаторов, я могу это сделать, но поля со многими отношениями каким-то образом, даже если они представляют собой массив идентификаторов при публикации, я получаю сообщение об ошибке:

Ошибка типа в /Albums/ Field ‘id’ ожидала число, но получила [<Порядок: 2B>] .

структура: Треки имеют заказы (где orders — это поле manytomany класса Orders)

В альбоме есть треки

Я могу публиковать в треках и указывать заказы в виде массива «заказы»: [2,4]

Когда я пытаюсь опубликовать в альбоме вместе с дорожками, я могу опубликовать дорожки с полями, которые НЕ ЯВЛЯЮТСЯ полями manytomany, но если я попытаюсь использовать поля manytomany, я получаю ошибку типа, упомянутую выше.

2B — это значение другого поля, а не идентификатор заказа, это значение поля, возвращаемого в

   def __str__(self) -> str:
        return (self.name)
 

Модели:

  class Orders(models.Model):
   name = models.CharField(max_length=100, unique=True)

    def __str__(self) -> str:
        return self.name

class Album(models.Model):
    title = models.CharField(max_length=150)
    description = models.TextField(blank=True)

    def __str__(self) -> str:
        return self.title


class Tracks(models.Model):
    name = models.CharField(default="Period Relationship",
                            max_length=100, blank=True)
    orders = models.ManyToManyField(Orders, blank=True)
    album = models.ForeignKey(
        Album, related_name="tracks", default=None, on_delete=CASCADE)

    def __str__(self) -> str:
        return (self.name)

 

Сериализаторы:

 class TracksSerializer(serializers.ModelSerializer):

    class Meta:
        model = Tracks
        fields = "__all__"

class Album(serializers.ModelSerializer):
    tracks = TracksSerializar(
        many=True)

    class Meta:
        model = ALbum
        fields = '__all__'

    def create(self, validated_data):
        tracks = validated_data.pop(
            'tracks')

        album = Album.objects.create(
            **validated_data)
        for tracks in tracks:
            Tracks.objects.get_or_create(
                album=album, **tracks)
            album.tracks.add(
                tracks)
        return album
class OrdersSerializer(serializers.ModelSerializer):
 
    class Meta:
        model = Orders
        fields = '__all__'


 

Число просмотров:

 class OrdersViewSet(viewsets.ViewSet):

    def list(self, request):
        orders = Orders.objects.all()
        serializer = OrdersSerializer(
            orders, many=True)
        return Response(serializer.data)

    def create(self, request):
        serializer = OrdersSerializer(data=request.data)

        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def retrieve(self, request, pk=None):
        queryset = Orders.objects.all()
        orders = get_object_or_404(queryset, pk=pk)
        serializer = OrdersSerializer(
            orders)
        return Response(serializer.data)
    def update(self, request, pk=None, **kwargs):
        partial = kwargs.pop('partial', False)
        orders = Orders.objects.get(pk=pk)
        serializer = OrdersSerializer(
            orders, data=request.data, partial=partial)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

    def destroy(self, request, pk=None):
        orders = Orders.objects.get(pk=pk)
        orders.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

class AlbumViewSet(viewsets.ViewSet):

    def list(self, request):
        album = Album.objects.all()
        serializer = AlbumSerializer(album, many=True)
        return Response(serializer.data)

    def create(self, request):
        serializer = AlbumSerializer(data=request.data)

        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def retrieve(self, request, pk=None):
        queryset = Album.objects.all()
        album = get_object_or_404(queryset, pk=pk)
        serializer = AlbumSerializer(album)
        return Response(serializer.data)

    def update(self, request, pk=None, **kwargs):
        partial = kwargs.pop('partial', False)
        album = Album.objects.get(pk=pk)
        serializer = AlbumSerializer(
            album, data=request.data, partial=partial)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

    def destroy(self, request, pk=None):
        album = Album.objects.get(pk=pk)
        album.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)



class TracksViewSet(viewsets.ViewSet):

    def list(self, request):
        tracks = Tracks.objects.all()
        serializer = TracksSerializaer(
            tracks, many=True)
        return Response(serializer.data)

    def create(self, request):
        serializer = TracksSerializaer(
            data=request.data)

        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def retrieve(self, request, pk=None):
        queryset = Tracks.objects.all()
        tracks = get_object_or_404(queryset, pk=pk)
        serializer = TracksSerializaer(
            tracks)
        return Response(serializer.data)

    def update(self, request, pk=None):
        tracks = Tracks.objects.get(
            pk=pk)
        serializer = TracksSerializaer(
            tracks, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def destroy(self, request, pk=None):
        tracks = Tracks.objects.get(
            pk=pk)
        tracks.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

 

Комментарии:

1. Возможно, вы захотите добавить код моделей, а не просто общее описание. Похоже, вы назначаете объект, когда он ожидает идентификатор. Вы можете сделать instance.pk , чтобы вернуть только id .

2. @Bobort отредактировал код, я использовал код в качестве упрощенного примера, поскольку у меня задействовано больше полей, но решение будет тем же

3. Ну, я вижу проблемы с вашим create методом в вашем Album сериализаторе. Вы перебираете tracks переменную, имя tracks которой перезаписывает все, что вы ввели в нее ранее. И вам не нужно выполнять add включение album , поскольку вы уже указали его get_or_create . Выньте оператор for and add . Я не думаю, что это решение, но оно приблизит вас. Кроме того, почему бы не использовать Django Rest Framework для всей этой сериализации?

4. @Bobort удаление добавления работает нормально. но удаление for просто вызывает у меня больше проблем, например, не использовать прямое назначение orders.set() и некоторые ограничения not null. Я новичок в Django, но я думал, что использую фреймворк Django Rest, что я делаю не так? Если я удалю for, каким должен быть второй аргумент в get_or_create?

5. Попробуйте создать экземпляр заказа -> Экземпляр альбома -> треки без manytomanyfield. Затем добавьте экземпляр Order во вновь созданные треки. Согласно документу django, поле «порядок» модели «Трек» должно получить значение после сохранения экземпляра трека. Я не уверен, решит ли это вашу проблему, но вы можете обратиться к нижеприведенному документу и попробовать в консоли, прежде чем изменять сериализаторы. docs.djangoproject.com/en/3.2/topics/db/examples/many_to_many