Ulm
Ulm

Reputation: 477

Use a single function for multiple serializer fields with different arguments

I have a serializer for a model with an image field, for which I have saved multiple different sized thumbnail images. I access them by returning their URL using the SerializerMethodField:

class GalleryImageSerializer(serializers.ModelSerializer):
    image_sm = serializers.SerializerMethodField()
    image_md = serializers.SerializerMethodField()
    image_lg = serializers.SerializerMethodField()
    image_compressed = serializers.SerializerMethodField()

    def get_image_sm(self, obj):
        return default_storage.url(f'{splitext(obj.image.name)[0]}/sm.jpg')

    def get_image_md(self, obj):
        return default_storage.url(f'{splitext(obj.image.name)[0]}/md.jpg')

    def get_image_lg(self, obj):
        return default_storage.url(f'{splitext(obj.image.name)[0]}/lg.jpg')

    def get_image_compressed(self, obj):
        return default_storage.url(f'{splitext(obj.image.name)[0]}/compressed.jpg')

This code works, but it kind of violates the "don't repeat yourself" guideline. As you can see, these are all duplicate SerializerMethodFields, with the only difference being the filename, eg 'lg.jpg', 'md.jpg', etc.

I'd much prefer to have only one function that I call with an argument for the filename, as an example(pseudocode):

class GalleryImageSerializer(serializers.ModelSerializer):
    image_sm = serializers.SerializerMethodField(filename='sm.jpg')
    image_md = serializers.SerializerMethodField(filename='md.jpg')
    image_lg = serializers.SerializerMethodField(filename='lg.jpg')
    image_compressed = serializers.SerializerMethodField(filename='compressed.jpg')

    def get_image(self, obj, filename=''):
        return default_storage.url(f'{splitext(obj.image.name)[0]}/{filename}')

Currently I am unable to find any way to achieve this. Reading the source code of SerializerMethodField, it doesn't seem to support it.

Is there any way to avoid creating duplicate functions for fields with arbitrary differences?

Upvotes: 0

Views: 543

Answers (1)

theguru42
theguru42

Reputation: 3378

You can add these fields in the to_representation method.

def to_representation(self, instance):
    ret = super().to_representation(instance)
    # add img urls to ret dict
    for name in ['sm', 'md', 'lg', 'compressed']:
        ret['image_' + name] = default_storage.url(f'{splitext(instance.image.name)[0]}/{name}.jpg')
    return ret

check the docs for more details: https://www.django-rest-framework.org/api-guide/serializers/#to_representationself-instance

Upvotes: 1

Related Questions