some nooby questions
some nooby questions

Reputation: 693

Null in response which should't exist Django

When I send request in Postman like this: enter image description here

it returns me all fields fine expect the profile_photo. profile_photo in response is null and I don't know what is the problem. It should be the new uuid photo name.

Here is my model:

class User(AbstractBaseUser, PermissionsMixin):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    email = models.EmailField(_('email address'), unique=True)
    first_name = models.CharField(max_length=150, blank=True)
    last_name = models.CharField(max_length=150, blank=True)
    city = models.CharField(max_length=150, blank=True)
    description = models.CharField(max_length=1000, blank=True) 
    profile_photo = models.CharField(max_length=500, blank=True)
    date_joined = models.DateTimeField(default=timezone.now)
    about = models.TextField(_(
        'about'), max_length=500, blank=True)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)

    objects = CustomAccountManager()
    object = models.Manager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name', 'city']

    def __str__(self):
        return self.email

This is my view:

class CustomUserUpdate(generics.UpdateAPIView):
    permission_classes = [IsAuthenticated]
    queryset = User.objects.all()
    serializer_class = UserUpdateSerializer

    def get_object(self):
        return self.request.user

This is my serializer. Here i am setting the new photo name. When I print the new name here like this: print(instance.profile_photo) it shows me the new file name fine. But in the response i get null.

class UserUpdateSerializer(serializers.ModelSerializer):
    profile_photo = serializers.FileField(required=False)
    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name', 'city', 'description', 'profile_photo')

    def __init__(self, *args, **kwargs):
        super(UserUpdateSerializer, self).__init__(*args, **kwargs)
        self.fields['email'].required = False
        self.fields['description'].required = False

    def update(self, instance, validated_data):
        if instance.id == self.context['request'].user.id:
            instance.email = validated_data.get('email', instance.email)
            instance.first_name = validated_data.get('first_name', instance.first_name)
            instance.last_name = validated_data.get('last_name', instance.last_name)
            instance.city = validated_data.get('city', instance.city)
            instance.description = validated_data.get('description', instance.description)
            uploaded_file = validated_data.get('profile_photo', None)
            if uploaded_file:
                validate_extension(uploaded_file.name)
                instance.profile_photo = handle_uploaded_file(uploaded_file)
            instance.save()
        return instance

def handle_uploaded_file(file):
    extension = os.path.splitext(file.name)[1]
    new_filename = f"{uuid.uuid4()}{extension}"

    destination = open(f'static/user/images/{new_filename}', 'wb+')
    for chunk in file.chunks():
        destination.write(chunk)

    destination.close()
    return new_filename

def validate_extension(filename):
    extension = os.path.splitext(filename)[1].replace(".", "")
    if extension.lower() not in ALLOWED_IMAGE_EXTENSIONS:
        raise serializers.ValidationError(
            (f'Invalid uploaded file type: {filename}'),
            code='invalid',
        )

Upvotes: 0

Views: 52

Answers (1)

Umar Hayat
Umar Hayat

Reputation: 4991

While sending requests you are passing file as input to the serializer. Serializer validates it and saves it. Till here it is perfectly fine.

Now while returning the response it expects a file from instance.profile_photo but to the serializer validator's surprise, it contains a string value (i.e UUID file name). The problem is here!

We got the bug point. Let's solve it.

To solve it, differentiate the names for the request(File) and response (File name i.e UUID string):

class UserUpdateSerializer(serializers.ModelSerializer):
    profile_image = serializers.FileField(required=False, write_only=True)
    profile_photo = serializers.ReadOnlyField()
    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name', 'city', 'description', 'profile_photo', 'profile_image')

    def __init__(self, *args, **kwargs):
        super(UserUpdateSerializer, self).__init__(*args, **kwargs)
        self.fields['email'].required = False
        self.fields['description'].required = False

    def update(self, instance, validated_data):
        if instance.id == self.context['request'].user.id:
            instance.email = validated_data.get('email', instance.email)
            instance.first_name = validated_data.get('first_name', instance.first_name)
            instance.last_name = validated_data.get('last_name', instance.last_name)
            instance.city = validated_data.get('city', instance.city)
            instance.description = validated_data.get('description', instance.description)
            uploaded_file = validated_data.get('profile_image', None)
            if uploaded_file:
                validate_extension(uploaded_file.name)
                instance.profile_photo = handle_uploaded_file(uploaded_file)
            instance.save()
        return instance

We have solved the bug!

Upvotes: 1

Related Questions