16

I have a custom user for authentication and want to create a serializer class for it my custom user's model is like this :

class User (AbstractUser):
        bio = models.TextField(max_length=500, blank=True)
        birth_date = models.DateField(null=True, blank=True)
        image=models.FileField(null=True , blank=True)

and my serializer is :

class UserSerializer (serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('username' ,'email' ,'password' ,'firstname' , 'last name' )

how could I mention that the password field is a password and its content must be hashed?

Mahdi Sorkhmiri
  • 356
  • 2
  • 4
  • 16
  • If you have customer User then have you mentioned that in settings.py etc. with all settings? I believe you need all fields into this model where I'm seeing very few, regarding hash password it can be set using Django built in functions to make hashable. – Anup Yadav Mar 09 '18 at 08:50
  • @AnupYadav I added my user class to settings and it's an instant of the original user class but does not Hash the password by its own – Mahdi Sorkhmiri Mar 09 '18 at 09:26
  • This won't you need to explicitly override the `save` or `create` (DRF) method – Anup Yadav Mar 09 '18 at 09:32

4 Answers4

41

to hash password, call:

make_password(origin_password)

example serializers.py:

from rest_framework import serializers
from django.contrib.auth.models import User
from django.contrib.auth.hashers import make_password


class UserSerializer(serializers.HyperlinkedModelSerializer):

    password = serializers.CharField(
        write_only=True,
        required=True,
        help_text='Leave empty if no change needed',
        style={'input_type': 'password', 'placeholder': 'Password'}
    )

    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'password')

    def create(self, validated_data):
        validated_data['password'] = make_password(validated_data.get('password'))
        return super(UserSerializer, self).create(validated_data)
HoangYell
  • 4,100
  • 37
  • 31
  • The greater of this approach is that the make_password method can also be used for not User serialzer method too. Thank you for your answer. – Elias Prado Jun 10 '21 at 13:58
8

Change serializers.py as below

class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ('username', 'email', 'password', 'firstname', 'last name')

    def create(self, validated_data):
        user = super().create(validated_data)
        user.set_password(validated_data['password'])
        user.save()
        return user

    def update(self, instance, validated_data):
        user = super().update(instance, validated_data)
        try:
            user.set_password(validated_data['password'])
            user.save()
        except KeyError:
            pass
        return user
JPG
  • 82,442
  • 19
  • 127
  • 206
  • this code you added hides the password field in getting request but it's still not hashed and look like a normal text – Mahdi Sorkhmiri Mar 09 '18 at 09:46
  • Did your password not hashed? Can you add your current response as screenshot or something ? – JPG Mar 09 '18 at 10:03
  • 1
    @MahdiSorkhmiri, I don't know how to hash it but to hide the text you can wirte it like this: password = serializers.CharField(write_only=True, style={'input_type': 'password'}) – Aman Sharma Jun 11 '18 at 03:35
  • This will write the raw password directly into the database, rather than hashing it via user.set_password (which itself uses make_password). Making it write_only is only half the job. – Oli Nov 16 '19 at 15:18
  • @Oli Yeah..you were right. Thanks for the correction and I have updated the answer :) – JPG Nov 16 '19 at 15:36
  • you need to call make_password to hash – Evren Bingøl Dec 19 '20 at 09:03
  • with this it keep showing on OPT request, but not on GET ones. perfect! thanks – Enzo Dtz May 20 '21 at 16:39
  • Just to remmember that set_password() is only for User model. For those who are looking to hash not User password you should use make_password method from auth.hashers. – Elias Prado Jun 10 '21 at 13:55
3

There was no special field for password in DRF. In my current project we used to define password field as CharField with write_only=True inside serializer class.

Shubho Shaha
  • 1,869
  • 1
  • 16
  • 22
3

The @MahdiSorkhmiri answer is working perfectly for me. Here is how my file is looking write now.

   class UserSerializer(serializers.ModelSerializer):
        email = serializers.EmailField(
        validators=[UniqueValidator(UserModel.objects.all())]
        )
        password = serializers.CharField(
        min_length=4,
        write_only=True,
        required=True,
        style={'input_type': 'password'}
        )
    def create(self, validated_data):
        fields = ['username', 'password', 'email']
        data = {f: validated_data.get(f) for f in fields}

        return UserModel.objects.create_user(**data)

    class Meta:
        model = UserModel
        fields = 'username email last_name first_name password'.split()
Mr.Rusev
  • 46
  • 2
  • 1
    Welcome to Stack Overflow! Here is a guide on [How to Answer](http://stackoverflow.com/help/how-to-answer). Please don't add "thanks" as answers. They don't actually provide an answer to the question, and can be perceived as noise by its future visitors. Once you earn enough reputation, you will gain privileges to upvote answers you like. This way future visitors of the question will see a higher vote count on that answer, and the answerer will also be rewarded with reputation points. See [Why is voting important](http://stackoverflow.com/help/why-vote). – help-info.de Apr 14 '19 at 13:35