2

I am experiencing a strange issue. I have been developing an application using Django and DRF along with react in frontend. My app has two models, Place and Cover. Every place has a cover image and here is the database schema.

Image Table

+----+---------------------+----------+----------------------+
| pk |        file         |  title   |     description      |
+----+---------------------+----------+----------------------+
|  1 | /media/my-image.jpg | My Image | My Image Description |
+----+---------------------+----------+----------------------+

Place Table

+----+------+-------+
| pk | code | cover |
+----+------+-------+
|  1 | abcd |     1 |
+----+------+-------+

My operation is simple. I will request for place details using the place code and DRF will return the details. And here is what I wrote initially.

class ImageSerializer(ModelSerializer):
    class Meta:
        model = Image
        fields = ["pk", "file", "title", "description"]

class PlaceDetailSerializer(ModelSerializer):
    cover = ImageSerializer()

    class Meta:
        model = Place
        fields = ["code", "cover"]

class PlaceDetailView(RetrieveAPIView):
    serializer_class = PlaceDetailSerializer
    permission_classes = []
    queryset = Place.objects.filter(deleted=False, published=True)
    lookup_field = 'code'
    lookup_url_kwarg = 'code'

And here is the output of the request

{
    "code": "3469324020",
    "cover": {
        "pk": 13,
        "file": "http://127.0.0.1:8000/media/my-image.jpg ",
        "title": "My Image",
        "description": ""
    }
}

Everything is fine so far. As I wanted the full url of my image and that's exactly what I have got. But the problem occurs when I start using SerializerMethodField()

class PlaceDetailSerializer(ModelSerializer):
    cover = SerializerMethodField()

    def get_cover(self, place):
        return ImageSerializer(place.cover).data

    class Meta:
        model = Place
        fields = ["code", "cover"]

And here is the new response after the changes

{
    "code": "3469324020",
    "cover": {
        "pk": 13,
        "file": "/media/my-image.jpg",
        "title": "My Image",
        "description": ""
    }
}

See? DRF is no longer returning absolute url but relative. I am curious why is that? Is it related to DRF context params??

I have also noticed that the absolute url doesn't work with APIView either.

class PlaceDetailSerializer(ModelSerializer):
    cover = ImageSerializer()

    class Meta:
        model = Place
        fields = ["code", "cover"]


class PlaceDetailView( APIView ):
    serializer_class = PlaceDetailSerializer
    permission_classes = []
    queryset = Place.objects.filter(deleted=False, published=True)
    lookup_field = 'code'
    lookup_url_kwarg = 'code'

    def get(self, request, *args, **kwargs):
        place = Place.objects.get(code=kwargs.get("code"))
        return Response(PlaceDetailSerializer(place).data)

It will also return the relative url as output.


Now I know that there are ways to return full url using get_absolute_url() or other functions. But I am just curious why this isn't working with SerializerMethodField or APIView. I hope if you know, you might be able to help me understand what's going on here.


1 Answer 1

5

You need to make the request available to the serializer, like so:

return Response(PlaceDetailSerializer(place, context={'request': request}).data)

return ImageSerializer(place.cover, context={'request': request}).data

Normally, Django Rest Framework does this for you, but if you invoke the serializer class manually (e.g. in a MethodField), you have to also pass the request as a context variable.

Check out how the FileField is serialized:

request = self.context.get('request', None)
if request is not None:
     return request.build_absolute_uri(url)
return url

If you don't pass in the request as a context variable, the serializer can't build the absolute URL.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.