Search code examples
djangorestdjango-rest-frameworkdjango-serializerdjango-validation

REST Django - Can't find context of request from within my validator


Please be gentle. I'm a Django newb and I find the level of abstraction just plain overwhelming.

My ultimate goal is to modify an image file on its way into the model. That part may or may not be relevant, but assistance came my way in this post which advised me that I should be making changes inside a validator: REST Django - How to Modify a Serialized File Before it is Put Into Model

Anyway, at the moment I am simply trying to get the context of the request so I can be sure to do the things to the thing only when the request is a POST. However, inside my validator, the self.context is just an empty dictionary. Based on what I have found out there, there should be a value for self.context['request']. Here is what I have:

Serializer with validator method:

class MediaSerializer(serializers.ModelSerializer):
    class Meta:
        model = Media
        fields = '__all__'

    def validate_media(self, data):
        print(self.context)
        #todo: why is self.context empty?
        #if self.context['request'].method == 'POST':
        #    print('do a thing here')
        return data

    def to_representation(self, instance):
        data = super(MediaSerializer, self).to_representation(instance)
        return data

The view along with the post method

class MediaView(APIView):
    queryset = Media.objects.all()
    parser_classes = (MultiPartParser, FormParser)
    permission_classes = [permissions.IsAuthenticated, ]
    serializer_class = MediaSerializer

    def post(self, request, *args, **kwargs):

        user = self.request.user
        print(user.username)

        request.data.update({"username": user.username})

        media_serializer = MediaSerializer(data=request.data)
        # media_serializer.update('username', user.username)
        if media_serializer .is_valid():
            media_serializer.save()
            return Response(media_serializer.data, status=status.HTTP_201_CREATED)
        else:
            print('error', media_serializer.errors)
            return Response(media_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

The Model:

class Media(models.Model):
    objects = None
    username = models.ForeignKey(User, to_field='username',
                                 related_name="Upload_username",
                                 on_delete=models.DO_NOTHING)
    date = models.DateTimeField(auto_now_add=True)
    #temp_media = models.FileField(upload_to='upload_temp', null=True)
    media = models.FileField(upload_to='albumMedia', null=True)
    #todo: potentially this will go to a temp folder, optimize will be called and then permananent home will be used -jjb
    #MEDIA_ROOT path must be /src/upload
    file_type = models.CharField(max_length=12)
    MEDIA_TYPES = (
        ('I', "Image"),
        ('V', "Video")
    )
    media_type = models.CharField(max_length=1, choices=MEDIA_TYPES, default='I')

    ACCESSIBILITY = (
        ('P', "Public"),
        ('T', "Tribe"),
        ('F', "Flagged")
    )

    user_access = models.CharField(max_length=1, choices=ACCESSIBILITY, default='P')

So I'm just trying to figure out how to fix this context problem. Plus if there are any other tips on how to get where I'm going, I'd be most appreciative.

PS I'm pretty new here. If I wrote this question in a way that is inappropriate for stack overflow, please be kind, and I will correct it. Thanks.


Solution

  • I don't think you need to worry about checking if the request is a POST inside the validate_media() method. Generally validation only occurs during POST, PATCH, and PUT requests. On top of that, validation only occurs when you call is_valid() on the serializer, often explicitly in a view, as you do in your post() function. As long as you never call is_valid() from anywhere other than post(), you know that it is a POST. Since you don't support patch() or put() in your view, then this shouldn't be a problem.

    inside my validator, the self.context is just an empty dictionary

    You must explicitly pass in context when creating a serializer for it to exist. There is no magic here. As you can see in the source code context defaults to {} when you don't pass it in.

    To pass in context, you can do this:

            context = {'request': request}
            media_serializer = MediaSerializer(data=request.data, context=context)
    

    Even better, just pass in the method:

            context = {'method': request.method}
            media_serializer = MediaSerializer(data=request.data, context=context)
    

    You can make the context dictionary whatever you want.