3

in DRF, is there any way to get a single nested image to show up in a view. In my example you can see that there are 2 photos listed. What would be the best solution to retrieve and display just that first photo? This view would be for a list of houses, and I don't want every pic to be displayed, as there could be some users uploading 30+ photos.

            "url": "http://127.0.0.1:8000/api/v1/listings/1/",
            "address": "8753 sherwood dr apt 111",
            "image_set": [
                {
                    "photo": "http://127.0.0.1:8000/media/listing_images/front-view.png"
                },
                {
                    "photo": "http://127.0.0.1:8000/media/listing_images/image34453.png
                }
            ]
        },


class ImageSerializerForListingDetail(serializers.ModelSerializer):
    photo = serializers.ImageField(use_url=True, allow_empty_file=True)
    class Meta:
        model = Image
        fields = ('photo', )
    def get_image_url(self, listing):
        return listing.photo.url


class ListingListSerializer(serializers.HyperlinkedModelSerializer):
    photo = ImageSerializerForListingDetail(many=True, required=False)
    class Meta:
        model = Listing
        fields = ('url', 'address', 'photo', )


class ListingViewSet(viewsets.ModelViewSet):
    queryset = Listing.objects.all().order_by('id')
    permission_classes = [IsOwnerOrReadOnly, ]
    serializer_classes = {
        'list': ListingListSerializer,
        'retrieve': ListingSerializer
    }
    default_serializer_class = ListingSerializer

    def get_serializer_class(self):
        return self.serializer_classes.get(self.action, self.default_serializer_class)

    def create(self, request, *args, **kwargs):
        serializer = ListingSerializer(data=request.data, files=request.FILES)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

current code I have just tried, returns an empty photo list.... #

class ImageSerializerForListingDetail(serializers.ModelSerializer):
    photo = serializers.ImageField(allow_empty_file=True)

    class Meta:
        model = Image
        fields = ('photo', )

    def get_image_url(self, listing):
        return listing.photo.url



class ListingListSerializer(serializers.HyperlinkedModelSerializer):
    first_image = ImageSerializerForListingDetail(many=True, required=False)

    class Meta:
        model = Listing
        fields = ('url', 'address', 'first_image', )

    def get_first_image(self, obj):
        first_image = Image.objects.filter(listing=obj).first()
        first_image_serializer = ImageSerializerForListingDetail(first_image)
        return first_image_serializer.data
master_j02
  • 377
  • 3
  • 13

2 Answers2

2

As I am not quite sure how your model is and which the first photo you would like to present(e.g. latest uploaded, first uploaded, latest id). I will use a generic example to explain the solution.

Try serializers.SerializerMethodField() to custom the field which you want to present the latest one.

Suppose there is a list of groups in a user model and you would like to present the latest group id in the user's detail.

Here is an example:

class UserSerializer(serializers.ModelSerializer):
    latest_group_id = serializers.SerializerMethodField()

    def get_latest_group_id(self, obj):
        return Group.objects.filter(user=obj).latest('id').id

Since you would like to present photo url rather than id, here is the pseudo code.

class UserProfileSerializer(serializers.ModelSerializer):
    latest_image = serializers.SerializerMethodField()

    def get_latest_image(self, obj):
        latest_image = Image.objects.filter(user=obj).latest('id')
        latest_image_serializer = ImageSerializerForListingDetail(latest_image)
        # Deal with edge cases, e.g. latest_image_serializer is not valid
        return latest_image_serializer.data
Jun Zhou
  • 1,077
  • 1
  • 6
  • 19
  • My goal is to just get the first image uploaded. I am only dealing with two models. A `Listing` model and an `Image` model. The image model has two fields, photo, and listing. Which the listing is a ForeignKey to the Listing model. I am toying around with your code now trying to find the right solution. – master_j02 Mar 04 '20 at 18:02
  • From the latest code you posted in your question, the first_image field in ListingListSerializer should be ```first_image = serializers.SerializerMethodField()``` – Jun Zhou Mar 04 '20 at 18:14
  • just fixed that lol. Still getting an empty queryset where my `first_image` field would be.. `{ "url": "http://127.0.0.1:8000/api/v1/listings/2/", "address": "4848 north florida dr" }` – master_j02 Mar 04 '20 at 18:18
  • Are there any images relating to your list(id=2)? – Jun Zhou Mar 04 '20 at 18:22
  • yeah, when I actually click into that url and go into the detail view, there are two photos associated with that listing. – master_j02 Mar 04 '20 at 18:34
  • It would be useful if you set up some breakpoints in the get_latest_image function to check whether there is an image instance returned or not. Also, you can check the serializer's data. – Jun Zhou Mar 04 '20 at 18:45
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/209061/discussion-between-jun-zhou-and-jmast). – Jun Zhou Mar 05 '20 at 10:00
1

You can pass only first item to your serializer:

def get_queryset(self):
    return  Listing.objects.all().order_by('id').first() if self.action == 'retrieve' else Listing.objects.all().order_by('id')
kamilyrb
  • 2,502
  • 3
  • 10
  • 25
  • How would I get the images to that listing? Some sort of extra filtering is what I am trying? Since the Images have a foreignkey to the Listing. – master_j02 Mar 04 '20 at 16:09
  • this is my Image model ```class Image(models.Model): photo = models.ImageField(blank=True, upload_to=get_image_filename) listing = models.ForeignKey(Listing, on_delete=models.CASCADE)``` – master_j02 Mar 04 '20 at 16:11
  • I did'nt understand what do you want. Can you explain with more detail? – kamilyrb Mar 04 '20 at 18:03
  • My goal is to just get the first image uploaded. I am only dealing with two models. A Listing model and an Image model. The image model has two fields, photo, and listing. Which the listing is a ForeignKey to the Listing model. I have updated the post, with the latest code I attempted. It is returning an empty query now. – master_j02 Mar 04 '20 at 18:09