When I send request in Postman like this:
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',
)
CodePudding user response:
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!
Cheers!