Search code examples
djangopython-3.xdjango-rest-frameworkdjango-rest-auth

Custom User model in rest-auth: RelatedObjectDoesNotExist


I am trying to implement the registration using django rest-auth library. I followed every instruction from the installation and usage guide, including the part with a custom user serializer. And here the problems begin. We register a new user, confirm the email and when I try to update the user, i get the same error:

"RelatedObjectDoesNotExist at /rest-auth/user/ User has no userprofile."

I can't figure out how to make registration to create simultaneously a user and a profile for him. I know that this question has been asked before, but I didn't find anything that would explain why is this happening. I am looking for a bare-simple WORKING example of registration using django-rest-auth and a custom User model

models.py:

class UserProfile(models.Model): 
     user = models.OneToOneField(User, primary_key=True, related_name='profile')
     tagline = models.CharField(max_length=140, null=True)
     created_at = models.DateTimeField(auto_now_add=True)
     updated_at = models.DateTimeField(auto_now=True)

     @receiver(post_save, sender=User)
     def create_profile_for_user(sender, instance=None, created=False, **kwargs):
        if created:
            UserProfile.objects.get_or_create(user=instance)

     @receiver(pre_delete, sender=User)
     def delete_profile_for_user(sender, instance=None, **kwargs):
        if instance:
           user_profile = UserProfile.objects.get(user=instance)
           user_profile.delete()

serilizers.py

class UserSerializer(UserDetailsSerializer):
    curriculumVitaeLink = serializers.CharField(source="userprofile.curriculumVitaeLink", required=False)
    class Meta(UserDetailsSerializer.Meta):
        fields = UserDetailsSerializer.Meta.fields + (
            'curriculumVitaeLink'
        )

    def update(self, instance, validated_data):
        profile_data = validated_data.pop('userprofile', {})
        curriculumVitaeLink = profile_data.get('curriculumVitaeLink')
        instance = super(UserSerializer, self).update(instance, validated_data)

        # get and update user profile
        profile = instance.userprofile
        if profile_data :
            profile.curriculumVitaeLink = curriculumVitaeLink
            profile.save()
        return instance

    def destroy(self, request, pk=None, **kwargs):
        request.user.is_active = False
        request.user.save()
        return Response(status=204)

Solution

  • RelatedObjectDoesNotExist error here means that corresponging UserProfile object was not created by the signal when User object was created. Based on the snippet in the question it might be becase of how signals were defined:

    Django signals need to be defined on module level, not as model instance methods - you need to shift indentation to the left:

     class UserProfile(models.Model): 
         user = models.OneToOneField(User, primary_key=True, 
         related_name='profile')
         tagline = models.CharField(max_length=140, null=True)
         created_at = models.DateTimeField(auto_now_add=True)
         updated_at = models.DateTimeField(auto_now=True)
    
    
     @receiver(post_save, sender=User)
     def create_profile_for_user(sender, instance=None, created=False, **kwargs):
        if created:
            UserProfile.objects.get_or_create(user=instance)
    

    This way both User and UserProfile objects should be created on registration.