0

I have this problem for a month.

I'm using abstractbasemodel and basemanagerto to create a login and signup API using rest framework.

However, when I create a user password, it is saved as raw data since I use set_password() method and custom model manager confuses me...

This is my code :

class UserProfileSerializer(serializers.ModelSerializer):    
    class Meta:
        model        = UserProfile
        fields       = ('id' ,'email' ,'name' ,'password')
        extra_kwargs = {
            'password':{
                'write_only':'True',
                'style': {'input_type': 'password'}
            }
        } 

        def create(self, validated_data):
            user = UserProfile.people.create_user(
                email = validated_data['email'],
                name  = validated_data['name'],
                password = validated_data['password']
            )

class UserProfileViewSet(viewsets.ModelViewSet):
    serializer_class = serializers.UserProfileSerializer
    queryset = models.UserProfile.people.all()
    authentication_classes = (TokenAuthentication, )
    permission_classes     = (UpdateOwnProfile, )
    filter_backends        = (SearchFilter, )
    search_fields          = ('name', 'email')


class UserLoginApiView(ObtainAuthToken):
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES

class UserProfileManager(BaseUserManager):
    def create_user(self, email, name, password=None):
        print("user model manager")
        if not email:
            raise ValueError('User Must Have an Email Address')
        email = self.normalize_email(email)
        user = self.model(email=email, name=name )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, name, password):
        user = self.create_user(email, name, password)
        user.is_superuser = True
        user.is_staff     = True
        user.save(using=self._db)
        return user

class UserProfile(AbstractBaseUser,PermissionsMixin):
    email           =         models.EmailField(max_length=255,unique=True)
    name            = models.CharField(max_length=255)
    is_active       = models.BooleanField(default=True)
    is_staff        = models.BooleanField(default=False)

    people = UserProfileManager()

    USERNAME_FIELD  = 'email'
    REQUIRED_FIELDS = ['name']

    def get_full_name(self):
        return self.name

    def get_short_name(self):
        return self.name

    def __str__(self):
        return self.email

class Profile(models.Model):
    user         =     models.OneToOneField(UserProfile,on_delete=models.CASCADE,relat    ed_name="Profile")
    location     =     models.CharField(max_length=100,blank=True,null=True)
    bio          =     models.CharField(max_length=100,blank=True,null=True)
    creationDate = models.DateTimeField(auto_now_add=True)
    follower     =     models.ManyToManyField(UserProfile,related_name="Following",blank=True)

    class Meta:
        verbose_name='Profile'
        verbose_name_plural='Profiles'

I also defined auth user model in settings :

AUTH_USER_MODEL='profiles.UserProfile'

to make sure Django uses my custom user model.

I don't know whats wrong as there is no error and only superusers that are created in terminal using manage.py are saved with hashed password.

Users which are created with my viewsets are saved with raw password.

First, I named the model manager "objects" and now, its people but the create user method wont run at all.

1
  • UserProfileSerializer's create function should return the newly created instance, can you add return user to the create function block Commented May 22, 2020 at 5:18

1 Answer 1

1

You can use django's built in hasher to create hashed password. It can be applied in .create method. First import from django.contrib.auth.hashers import make_password and then modify .create() method,

    def create(self, validated_data):
        user = UserProfile.people.create_user(
            email = validated_data['email'],
            name  = validated_data['name'],
            password = make_password(validated_data['password']) # here
        )
        return user

Or

if you don't override the .create() method then add the following validate_password method in serializer, The validate_password is ran, everytime a new object has to be created

class UserProfileSerializer(serializers.ModelSerializer):    
    class Meta:
        model        = UserProfile
        fields       = ('id' ,'email' ,'name' ,'password')
        extra_kwargs = {
            'password':{
                'write_only':'True',
                'style': {'input_type': 'password'}
            }
        } 
    def validate_password(self, value: str) -> str:
        return make_password(value)
Sign up to request clarification or add additional context in comments.

1 Comment

indent error at the last two line | the validate_password function must be under UserProfileSerializer not under class

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.