Django REST Framework and FileField absolute url

Mark Semsel picture Mark Semsel · May 28, 2014 · Viewed 30k times · Source

I've defined a simple Django app that includes the following model:

class Project(models.Model):
    name = models.CharField(max_length=200)
    thumbnail = models.FileField(upload_to='media', null=True)

(Technically yes, that could have been an ImageField.)

In a template, it's easy enough to include the MEDIA_URL value (duly coded in settings.py) as a prefix to the thumbnail URL. The following works fine:

<div id="thumbnail"><img src="{{ MEDIA_URL }}{{ current_project.thumbnail }}" alt="thumbnail" width="400" height="300" border="0" /></div>

Using DRF, I've defined a HyperlinkedModelSerializer descendant called ProjectSerializer:

class ProjectSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Project
        fields = ( 'id' ,'url', 'name', 'thumbnail')

And I've defined a very straightforward ModelViewSet descendant:

class ProjectViewSet(viewsets.ModelViewSet):
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer

A sample of the resulting JSON looks like this:

{
    "id": 1, 
    "url": "http://localhost:8000/api/v1/projects/1/", 
    "name": "Institutional", 
    "thumbnail": "media/institutional_thumb_1.jpg"
}

I have not yet been able to figure out how to provide a thumbnail field that includes the full url to the image in my project's JSON representation.

I would think that I would need to create a custom field in the ProjectSerializer, but have not been successful.

Answer

johntellsall picture johntellsall · May 28, 2014

Try SerializerMethodField

Example (untested):

class MySerializer(serializers.ModelSerializer):
    thumbnail_url = serializers.SerializerMethodField('get_thumbnail_url')

    def get_thumbnail_url(self, obj):
        return self.context['request'].build_absolute_uri(obj.thumbnail_url)

The request must available to the serializer, so it can build the full absolute URL for you. One way is to explicitly pass it in when the serializer is created, similar to this:

serializer = MySerializer(account, context={'request': request})