djangodjango-rest-frameworkcloudinary

How can I serialize Cloudinary fields?


I'm trying to use Cloudinary SDK's for Svelte and Django. I have a model with CloudinaryField:

class Room(models.Model):
    ...
    avatar = CloudinaryField("image")

class UserRoom(models.Model):
    room = models.ForeignKey(Room, on_delete=models.CASCADE)
    ...

and a serializer for the UserRoom:

class UserRoomSerializer(ModelSerializer):
    user = UserSerializer()
    last_message = SerializerMethodField()

    def get_last_message(self, obj):
        return MessageSerializer(obj.room.message_set.first()).data

    class Meta:
        model = UserRoom
        fields = "__all__"
        depth = 1

I want to use Cloudinary's svelte component <CldImage /> and I need to pass an image public id into it. But when I make a request, I get an image path, not id:

{
  "id": 1,
  "user": {
    ...
  },
  "last_message": {
    ...
  },
  "unread_messages": 0,
  "room": {
    "id": "49c33134-cc9f-43e0-b524-b05e9387602d",
    "name": "test",
    "avatar": "image/upload/v1728304120/sz8h5f5oqbtc95cfxbvx.jpg" // THIS LINE IS A PATH, NOT AN ID
  }
}

How do I make DRF send an id, not a path?


Solution

  • The reason this happens is because a CloudinaryField has no dedicated field for the Django REST framework (DRF) [drf-doc]. That means it will try to call the .value_to_string(…) method [GitHub] of the corresponding field, which returns the path.

    We can define a custom serializer however, that takes the .public_id of the CloudinaryResource:

    class RoomSerializer(ModelSerializer):
        avatar = models.CharField(source='avatar.public_id', read_only=True)
    
        class Meta:
            model = Room
            fields = '__all__'
    
    
    class UserRoomSerializer(ModelSerializer):
        user = UserSerializer()
        last_message = SerializerMethodField()
        room = RoomSerializer()
    
        def get_last_message(self, obj):
            return MessageSerializer(obj.room.message_set.first()).data
    
        class Meta:
            model = UserRoom
            fields = '__all__'
            depth = 1