Nikko
Nikko

Reputation: 1572

Why create method is not called in django serializer?

I am want to be able to POST an entry to a ManyToManyField (ImageTag) one by one. I am using extra actions to make a nested endpoint under an Image.

I want to be able to POST an entry one POST at a time.

localhost:8000/my_app/images/IMG_123/image_tags/

I want to override the create method on the Serializer to do this. But the problem is its not getting called. Why?

This is my source code:

#models.py
class ImageTag(models.Model):
    name = models.CharField()
    description = models.CharField()

class Image(models.Model):
    image_id = models.CharField(unique=True)
    image_tags = models.ManyToManyField(ImageTag, blank=True)
    ...

#serializers.py
class ImageSerializer(serializers.ModelSerializer):

    class Meta:
        model = Image
        fields = '__all__'

class ImageTagSerializer(serializers.ModelSerializer):
    image_tags = serializers.StringRelatedField(many=True)

    class Meta:
        model = Image
        fields = ('image_tags',)

    def to_internal_value(self, data):
        return data

    def create(self, validated_data):
        print("GOTHERE")
        print("VALI", validated_data)
        return validated_data

#views.py
class ImageExtraAction(viewsets.ModelViewSet):

    @action(detail=True, methods=['get', 'post', 'delete'])
    def image_tags(self, request, capture_id=None):
        capture = self.get_object()

        serializer = ImageTagSerializer(capture, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class ImageTagViewSet(ImageExtraAction, viewsets.ModelViewSet):
    queryset = Image.objects.all()
    serializer_class = ImageSerializer
    lookup_field = 'image_id'
    ...

#urls.py
router.register(r'images', ImageTagViewSet, basename='image')

Upvotes: 1

Views: 2942

Answers (3)

Mohammed Mwijaa
Mohammed Mwijaa

Reputation: 76

The .create() method is not called because you are not creating, rather updating an instance. To create an instance use:

serializer = ImageTagSerializer(data=request.data)

Upvotes: 1

Blusky
Blusky

Reputation: 3784

You try to put everything in your @action() function, as if it was a new viewsets.ModelViewSet. It's not working that way.

If you want to have all the mixins of viewsets.ModelViewSet, you have to create a separate ModelViewSet, or reimplement all methods in your action (see, in your image_tags(), the HTTP method is not even used)

Upvotes: 1

JPG
JPG

Reputation: 88519

Because you are passing the instance too while initializing the serializer.

serializer = ImageTagSerializer(capture, data=request.data)

Here, the capture is the model instance, at that time DRF thinks it is an update operation hence, DRF uses the update(...) method of the serializer.

Upvotes: 4

Related Questions