DRF ImageField serializes entire URL with domain name

Hello,

I came across issue which I cannot resolve. Depending on situation i get different serialization of file URL. I have UserProfile model with profile_picture field:

class UserProfile(models.Model):
    ...
    profile_picture = models.FileField(
        upload_to="profile_pictures/",
        storage=FileSystemStorage(base_url=settings.MEDIA_URL),
        default="profile_pictures/default.png",
    )

In my user detail view when I am serializing UserProfile object using standard ModelSerializer I get relative url path (without domain name and port) e.g. {profile_picture: “/media/profile_pictures/IMG_0007e2.jpg”, … }. However, in my view for updating profile picture:

class UserProfilePictureUpdate(generics.UpdateAPIView):
    queryset = UserProfile
    serializer_class = UserProfilePictureSerializer
    permission_classes = (permissions.IsAuthenticated, IsHisResource)
    parser_classes = (MultiPartParser,)

when I successfully upload image on the server I get full url in response body e.g. { profile_picture: “http://localhost:8000/media/profile_pictures/IMG_0007e2.jpg” }. In both cases serializes looks exactly the same, except UserProfile serializer has more fields than UserProfilePicture serializer. I tried to change use_url flag for ImageField but it doesn’t help (when its True domain name shows and when its False /media/ part is neglected)

Does anyone knows what can be the issue here?

Hi!

Could you share both serializers? Or at least the relevant field.
Is UserProfilePicture also a model serializer?

Sure,

This is UserProfilePictureSerializer used for updating profile picture:

class UserProfilePictureSerializer(serializers.ModelSerializer):

    class Meta:
        model = UserProfile
        fields = ("profile_picture",)

And here is UserProfielSerializer used in detail view:

class UserProfileSerializer(serializers.ModelSerializer):
    ...

    class Meta:
        model = UserProfile
        fields = ("country", "city", "profile_picture", "gender", "gender_display", "date_of_birth")
        read_only_fields = ("profile_picture",)

I don’t think it should matter, but in my case UserProfileSerializer is used as a nested serializer in another serializer and UserProfilePictureSerializer is used “directly” in the update view.

I’m sorry, I’m not following what you’re asking here. I’ve read where you’ve described the differences in the situations, but not what you’re looking for. What is it that you’re trying to have happen?

I am looking for the consistent serializer behavior in both scenarios. Specifically, after successful profile picture update I would like to receive response like this {profile_picture: “/media/profile_pictures/new_image.jpg”} and not like this { profile_picture: “http://localhost:8000/media/profile_pictures/new_image.jpg” }.

From what I can follow in the code, what you’re getting as output from the upload is what I would expect it to be. Notice that you’re specifying “profile_pictures” as “upload_to”. So the use_url=False would return profile_pictures/filename', while use_url=True` is supposed to return a full URL, which includes the protocol:host component.

In the detail view, however, it appears that it’s retrieving the url attribute of the field.

My guess would be then, if you want the url attribute of the field to be returned from the submission, you could override the to_representation method in your UserProfilePictureSerializer to retrieve the url attribute of that field and replace what the base class serializer returns by default.

1 Like