Search code examples
djangodjango-rest-frameworkdjango-serializer

I am getting a None type for my request in serializer after Patch


I am making a test that partial updates or patch some fields in my Product model. I should be enable to update any fields in my Product model. In my serializer, I have a url builder from the request object. However, request is not passed on my serializer or it is a None type. Thus, I am getting an error: AttributeError: 'NoneType' object has no attribute 'build_absolute_uri'

How do I pass a request to my serializer?

def test_patch_products(self):
    data = {
    'description': 'This is an updated description.',
    'type': 'New'
    }
    ...
    ...
    response = self.client.patch('/data/products/1/',
        data=data, format='json')

In my view:

def partial_update(self, request, pk=None):
    product= get_object_or_404(Product, pk=pk)

    serializer = ProductSerializer(product,
        data=self.request.data, partial=True,
        )

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

In my serializer:

class ProductSerializer(serializers.ModelSerializer):
    uploaded_by= serializers.StringRelatedField()
    thumbnail = serializers.SerializerMethodField()

    class Meta:
        model = CaptureGroup
        fields = ('__all__')

    def get_thumbnail(self, object):
        request = self.context.get('request') # request is None here
        thumbnail = object.thumbnail.url
        return request.build_absolute_uri(thumbnail) # here is the url builder

Solution

  • In your view, you can pass some additional context to your serializer. That's useful to manipulate your request.

    # views.py
    
    def partial_update(self, request, pk=None):
        product= get_object_or_404(Product, pk=pk)
    
        serializer = ProductSerializer(product,
            data=request.data, partial=True,
            context={'request': request}, # you're missing this line
            )
        # ...
    

    And then you can manipulate it your serializer with self.context.get('request') but I see you already got that part in your code.

    In case you would like more information, here is the link to DRF documentation about this.