Home > database >  Extended user class properties not updating
Extended user class properties not updating

Time:04-05

Would like to allow users to update their profile, getting the error

Field name 'city' is not valid for model 'User'.

For context, I extended my default user class in models.py:

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    city = models.CharField(max_length=50,blank=True)
    country = models.CharField(max_length=50, blank=True)
    bio = models.CharField(max_length=500, blank=True)
    profile_pic = models.ImageField(upload_to='profile/%Y/%m/%d', default='media/placeholder.png', blank=False, null=False)

    @receiver(post_save, sender=User)
    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            Profile.objects.create(user=instance)

    @receiver(post_save, sender=User)
    def save_user_profile(sender, instance, **kwargs):
        instance.profile.save()

When a user updates a profile I use this endpoint in urls.py:

path('update_profile/<int:pk>', views.UpdateProfileView.as_view(), name='update_profile'),

Here is my UpdateProfileView:

class UpdateProfileView(generics.UpdateAPIView):
    queryset = User.objects.all()
    serializer_class = UpdateUserSerializer
    def profile(request):
        if request.method == 'PUT':
            try:
                user = User.objects.get(id=request.user.id)
                serializer_user = UpdateUserSerializer(user, many=True)
                if serializer_user.is_valid():
                    serializer_user.save()
                    return Response(serializer_user)
            except User.DoesNotExist:
                return Response(data='no such user!', status=status.HTTP_400_BAD_REQUEST)

and my serializers.py:

class UpdateUserSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(required=False)

    class Meta:
        model = User
        fields = ['username', 'email', 'password', 'first_name', 'last_name','city','country']
        extra_kwargs = {'username': {'required': False},
                        'email': {'required': False},
                        'password': {'required': False},
                        'first_name': {'required': False},
                        'last_name': {'required': False},
                        'city': {'required': False},
                        'country': {'required': False}}


        def validate_email(self, value):
            user = self.context['request'].user
            if User.objects.exclude(pk=user.pk).filter(email=value).exists():
                raise serializers.ValidationError({"email": "This email is already in use."})
            return value

        def validate_username(self, value):
            user = self.context['request'].user
            if User.objects.exclude(pk=user.pk).filter(username=value).exists():
                raise serializers.ValidationError({"username": "This username is already in use."})
            return value

        def update(self, instance, validated_data):
            #re-writing updated profile info from request
            user = self.context['request'].user

            if user.pk != instance.pk:
                raise serializers.ValidationError({"authorize": "You don't have permission for this user."})

            instance.first_name = validated_data['first_name']
            instance.last_name = validated_data['last_name']
            instance.email = validated_data['email']
            instance.username = validated_data['username']
            instance.profile.city = validated_data['city']
            instance.profile.country = validated_data['country']
            instance.profile.bio = validated_data['bio']

            instance.save()

            return instance

Please let me know where I am going wrong

CodePudding user response:

In this part of the serializer:

fields = ['username', 'email', 'password', 'first_name', 'last_name','city','country']

'city' is not an attribute of User, it's an attribute of Profile. In order for DRF to update it, it needs to know how to access it.

Example:

class UpdateUserSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(required=False)
    city = serializers.CharField(source='profile.city')
    [...]

CodePudding user response:

like @Nick ODell said

"'city' is not an attribute of User, it's an attribute of Profile. In order for DRF to update it, it needs to know how to access it."

but couldn't we just change the model the serializer class is using like

class UpdateUserSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(required=False)

    class Meta:
        model = Profile
        fields = ['username', 'email', 'password', 'first_name', 'last_name','city','country']
        extra_kwargs = {'username': {'required': False},
                        'email': {'required': False},
                        'password': {'required': False},
                        'first_name': {'required': False},
                        'last_name': {'required': False},
                        'city': {'required': False},
                        'country': {'required': False}}
  • Related