Django接口响应中profile_photo字段为Null问题求助
问题描述
在Postman中发送用户更新请求后,接口返回的其他字段均正常,但profile_photo字段为Null——该字段本应返回新生成的UUID格式文件名。在Serializer的update方法中打印instance.profile_photo能正常显示新生成的文件名,但接口响应中该字段却始终为Null。
相关代码
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
View代码
class CustomUserUpdate(generics.UpdateAPIView): permission_classes = [IsAuthenticated] queryset = User.objects.all() serializer_class = UserUpdateSerializer def get_object(self): return self.request.user
Serializer代码
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', )
问题原因与解决方案
问题原因
Serializer中把profile_photo定义为FileField,但Model里该字段是CharField。当序列化返回数据时,FileField会尝试从实例中获取文件对象,而非存储的字符串文件名,因此无法匹配到有效内容,最终返回Null。
解决方案
有两种简洁的修复方式:
方式一:区分读写字段
将profile_photo的FileField设置为write_only=True,让序列化输出时自动使用Model默认的CharField返回存储的文件名:
class UserUpdateSerializer(serializers.ModelSerializer): # 仅用于接收上传文件,不参与输出序列化 profile_photo = serializers.FileField(required=False, write_only=True) class Meta: model = User fields = ('email', 'first_name', 'last_name', 'city', 'description', 'profile_photo') # 指定该字段为只读,确保输出时返回存储的字符串 read_only_fields = ('profile_photo',)
方式二:覆盖to_representation方法
手动指定profile_photo的返回值,强制输出实例中存储的字符串:
class UserUpdateSerializer(serializers.ModelSerializer): profile_photo = serializers.FileField(required=False) class Meta: model = User fields = ('email', 'first_name', 'last_name', 'city', 'description', 'profile_photo') # 保留原有__init__和update方法... def to_representation(self, instance): data = super().to_representation(instance) # 替换FileField的输出为实例中存储的文件名 data['profile_photo'] = instance.profile_photo return data
两种方式都能解决问题,推荐第一种,更符合DRF的字段设计规范,明确区分输入与输出的字段类型。
内容的提问来源于stack exchange,提问作者some nooby questions
相关产品推荐
相关产品推荐

