Matúš Bartko
Matúš Bartko

Reputation: 2457

How to add additional data before serializer validation/save in DRF?

So I have this class:

class MyClass(models.Model):    
    name = models.CharField(max_length=100)    
    created_time = models.DateTimeField(auto_now_add = True)
    modified_time = models.DateTimeField(auto_now = True)

and then other class representing related photos to MyClass:

class MyPhoto(models.Model):
    myclass = models.ForeignKey(MyClass, unique=False, related_name='photos')
    photo = models.ImageField(upload_to='photos',blank=False)

I would like to create an endpoint, which will handle photo uploads (content type will be multipart and id of associted myclass will be passed in url), so this is what I have:

urls.py:

router = routers.DefaultRouter()    
router.register(r'photos/(?P<myclass_id>\d+)',PhotoViewSet)

viewset:

class PhotoViewSet(CreateModelMixin,
                    viewsets.GenericViewSet):
    queryset = MyPhoto.objects.all()
    serializer_class = serializers.PhotoAlterSerializer
    parser_classes = (parsers.MultiPartParser,)

    def create(self, request, *args,**kwargs):
        myclass = MyClass.objects.get(pk=kwargs['myclass_id'])
        serializer = serializers.PhotoAlterSerializer(data=request.data,context={'request': request})
        if serializer.is_valid(raise_exception=True):
            photo=serializer.save(myclass=myclass)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

and serializer:

class PhotoAlterSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = MyPhoto
        fields = ('myclass','photo')

as you can see Im adding additional attribute myclass to the serializer.save(myclass=myclass) method.

However if I upload photo and correctly pass myclass id in url, I get This field is required. error. If I add correct hyperlink to the myclass into uploaded multipart form with photo, request will pass validation and then myclass from form will be replaced by myclass I got from url id.

How can I make this work, so if I post only photo to the url http://blabla/api/photos/2 the instance of this photo and myclass with pk=2 will be saved to db?

Upvotes: 2

Views: 2982

Answers (1)

almalki
almalki

Reputation: 4775

This is because you specified myclass in the fields meta of your serializer. This makes DRF requires and validates it as part of the POST data. Any field that you would set yourself should not be part of the serializer fields. So, all you need to make it work is to remove myclass from Meta.fields.

class PhotoAlterSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = MyPhoto
        fields = ('photo', )

Upvotes: 1

Related Questions