Ryan
Ryan

Reputation: 127

Django rest framework updating a OneToOne field

I have a User model that inherits from AbstractUser which has an email field. And a profile model that has an OneToOne relation with the User model

class User(AbstractUser):
    email = models.EmailField(unique=True)

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    phone = models.CharField(max_length=13, validators=[phone_regex], unique=True, null=True, blank=True)
    birth_date = models.DateField(blank=True, null=True)
    about = models.TextField(max_length=2000, blank=True)

    def __str__(self):
        return f"{self.user.first_name} {self.user.last_name}"

view.py

class ProfileViewSet(ModelViewSet):
    ....

    @action(detail=False, methods=["GET", "PUT"], permission_classes=[IsAuthenticated])
    def me(self, request, *args, **kwargs):
       
        profile = Profile.objects.get(user_id=request.user.id)

        if request.method == "GET":
            serializer = ProfileSerializer(profile)
            return Response(serializer.data)
        elif request.method == "PUT":
            serializer = ProfileSerializer(profile, request.data)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data)

serializers.py

class ProfileSerializer(serializers.ModelSerializer):
    user = CurrentUserSerializer()

    def update(self, instance, validated_data):
        user_data = validated_data.pop('user')
      
        user_ser = CurrentUserSerializer(instance=instance.user, data=user_data)
        if user_ser.is_valid():
            user_ser.save()
      
        instance.phone = validated_data.get('phone', instance.phone)
        instance.birth_date = validated_data.get('birth_date', instance.birth_date)
        instance.about = validated_data.get('about', instance.about)
        instance.save()
        return instance

    class Meta:
        model = Profile
        fields = [
            'id',
            'user',
            'phone',
            'birth_date',
            'about',

        ]

Now when I try to update a user profile I get status: 400 Bad Request error

{
    "user": {
        "email": [
            "user with this email already exists."
        ]
    }
}

using patch instead of put or partial=True doesn't change anything I still get this error. What can I do here?

Upvotes: 0

Views: 796

Answers (2)

Ryan
Ryan

Reputation: 127

Instead of a nested serializer I used serializer fields and my problem was solved. I'm not sure if it's a good approach or not.

class ProfileSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(source='user.email')
    first_name = serializers.CharField(source='user.first_name')
    last_name = serializers.CharField(source='user.last_name')

    def update(self, instance, validated_data):
        user_data = validated_data.pop('user')
        user = instance.user

        user_ser = CurrentUserSerializer(instance=user, data=user_data)
        if user_ser.is_valid():
            user_ser.save()

        instance.phone = validated_data.get('phone', instance.phone)
        instance.birth_date = validated_data.get('birth_date', instance.birth_date)
        instance.about = validated_data.get('about', instance.about)
        instance.save()
        

    class Meta:
        model = Profile
        fields = [
            'id',
            'email',
            'first_name',
            'last_name',
            'phone',
            'birth_date',
            'about',

        ]

Upvotes: 0

lord stock
lord stock

Reputation: 1201

The thing is you are creating new record on data base and It is not permitted

class ProfileSerializer(serializers.ModelSerializer):
    user = CurrentUserSerializer()

    def update(self, instance, validated_data):
        user_data = validated_data.pop('user')
        try:
           user=User.objects.get(pk=instance.user.id)
        except User.DoesNotExist:
               raise ValidationError("User already exist")
           #now with user instance  you can save the email or do whatever 
             you want
           user.email = "[email protected]")
           user.save()

       
      
        
      
        instance.phone = validated_data.get('phone', instance.phone)
        instance.birth_date = validated_data.get('birth_date', instance.birth_date)
        instance.about = validated_data.get('about', instance.about)
        instance.save()
        return instance

    class Meta:
        model = Profile
        fields = [
            'id',
            'user',
            'phone',
            'birth_date',
            'about',

        ]

Upvotes: 1

Related Questions