0

I have a model that accepts an image which is not required.

I'm trying to provide a link to a default image so that when a user later requests the model, I can send them the default image.

I'm using DRF so I don't necessarily have access to reverse inside a view; based on this response I'm trying to achieve the functionality in the model itself.

# models.py
class Widget(models.Model):
...    
    def image_url(self):

        '''
        Returns the url of the image for the model instance.

        If no image is found, return the path to the default meal image.
        '''
        if self.image and hasattr(self.image, 'url'):
            return self.image.url
        else:
            return settings.STATIC_URL + 'img/default/meal.png'

And in my serializer I just add the field instead of the image:

#serializers.py
class WidgetSerializer(serializers.HyperlinkedModelSerializer):
...
    class Meta:
        model = Widget
        fields = ('image_url',
        ...
        )

However, this of course only gives me the relative path of the image, /static/img/default/meal.png instead of something like http://localhost:8010/static/img/default/meal.png.

How can I get the base name of the url inside the model so I can respond with the full url? Is this even the right approach?

Also, as a side note, I just visited http://localhost:8010/static/img/default/meal.png in my browser, and it says the image could not be found. Any ideas about this as well?

--EDIT--

I sort of figured out how to get this working in the view. As of right now though, it only works for a detail view and I'd have to copy the same code into the list view for it to work, which I'm reluctant to do for DRY reasons.

The ideal would be to get the full url of the default image in the serializer, but I'm still not sure how to access the request object there.

# views.py
class WidgetDetail(APIView):

    def get_object(self, pk):
        try:
            return Widget.objects.get(pk=pk)
        except Widget.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        widget = self.get_object(pk)
        serializer = WidgetSerializer(
            widget,
            context={'request': request},
        )
        serialized_data = serializer.data

        if not widget.image:
            serialized_data['image'] = request.build_absolute_uri(
                settings.STATIC_URL + 'img/default/widget.png')
            # print(serialized_data['image'])

        return Response(serialized_data)
...

class WidgetList(APIView):

    def get(self, request, format=None):
        widgets = Widget.objects.all()
        serializer = WidgetSerializer(
            widgets,
            many=True,
            context={'request': request},
        )
        #... Would need to replace null urls here....
        return Response(serializer.data)

However, since I'm passing context to the serializer, I should be able to access it there, no?

sonarforte
  • 1,588
  • 15
  • 18

1 Answers1

3

view.py:

data = WidgetSerializer(wight, context={'request': request}).data

serializer.py

class WidgetSerializer(serializers.HyperlinkedModelSerializer):
...
    class Meta:
        model = Widget
        fields = ('image',
        ...
        )

add context={'request': request} to your serializer will get the full path of your image.more info here.


If you want to set it in serializer:

class WidgetSerializer(serializers.HyperlinkedModelSerializer):
    image = serializers.SerializerMethodField()
    class Meta:
        model = Widget
        fields = ('image',
        ...
        )

    def get_image(self, instance):
        request = self.context.get('request')
        return request.build_absolute_uri(instance.get_image())

model.py

class Widget(models.Model):
...    
    def get_image(self):
        if self.image:
            return self.image.url
        else:
            return settings.STATIC_URL + 'img/default/meal.png'
Ykh
  • 7,567
  • 1
  • 22
  • 31
  • So how do I get the context inside of the serializer? I'm trying to do `context = self.context` inside the serializer but that's not working because `self` is undefined.... – sonarforte Jun 20 '17 at 01:21
  • `data = WidgetSerializer(wight, context={'request': request}).data` is in your view.py not inside the serializer – Ykh Jun 20 '17 at 01:35
  • Oh are you suggesting I get the data in the view, then replace the image_url with the correct one, then continue on with the view? – sonarforte Jun 20 '17 at 01:47
  • Done. There's no way to get it in the serializer? – sonarforte Jun 20 '17 at 02:44