19

I'm trying to create an API for my user registration using Django Rest Framework. I created a serializer by following the step from the api-guide

class CreateUserSerializer(serializers.ModelSerializer):
  class Meta:
    model = User
    fields = ('email', 'username', 'password')
    extra_kwargs = {'password': {'write_only': True}}

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

However, I keep getting the Invalid password format or unknown hashing algorithm. for my newly created user. I've tried to use make_password from django.contrib.auth.hashers, but I still can't resolve this issue.

Thanks

1

8 Answers 8

32

You can try it in this way

from django.contrib.auth.hashers import make_password

user = User.objects.create(
       email=validated_data['email'],
       username=validated_data['username'],
       password = make_password(validated_data['password'])
)
Sign up to request clarification or add additional context in comments.

1 Comment

For anyone spending way too much finding an answer to why user.set_password(password) this solution finally works when we're setting the password during user creation. It seems to me that I had race condition issues as I tried to create the user first via bulk_create, and set the password later.
8

You can overwrite the perform_create method in CreateAPIView

from rest_framework.generics import CreateAPIView

class SignUpView(CreateAPIView):
    serializer_class = SignUpSerializers

    def perform_create(self, serializer):
        instance = serializer.save()
        instance.set_password(instance.password)
        instance.save()

2 Comments

this will save the instance twice
Yes, it won't be the best way to do it
7

In the serializer redefine the function create with this:

from django.contrib.auth.hashers import make_password

class UserSerializer(ModelSerializer):

    def create(self, validated_data):
        validated_data['password'] = make_password(validated_data['password'])
        return super(UserSerializer, self).create(validated_data)

And this all! :D

Comments

6

You could also use a field validation function for the password field by adding a validate_password method to your serializer and make it return the hash.

from rest_framework.serializers import ModelSerializer
from django.contrib.auth.hashers import make_password


class UserSerializer(ModelSerializer):
    class Meta:
        model = backend.models.User
        fields = ('username', 'email', 'password',)

    validate_password = make_password

Comments

1

You can do this in the views perform_create method:

from django.contrib.auth.hashers import make_password



def perform_create(self, instance):
        current_user = self.request.user
        user_exists = CustomUser.objects.filter(
            email=self.request.data['email']).first()
        if user_exists:
            raise MethodNotAllowed
        else:
            instance.save(is_active=False, is_confirmed=False,
                          password=make_password(self.request.data['password']))

Comments

0

Another simple solution is to use User.objects.create_user() in your create method like below

def create(self, validated_data):
    user = User.objects.create_user(**validated_data)
    return user

Comments

0

Another solution is to create a custom field. The advantage is that it works for both create and update. It also provides automatic documentation.

fields.py

class PasswordField(serializers.CharField):
    def __init__(self, *args, **kwargs):
        kwargs.update(
            {
                "help_text": " ".join(
                    password_validation.password_validators_help_texts()
                ),
                "max_length": 128,
                "style": {"input_type": "password"},
                "write_only": True,
            }
        )
        super().__init__(*args, **kwargs)

    def to_internal_value(self, data):
        password_validation.validate_password(data)
        return make_password(data)

serializers.py

class UserSerializer(serializers.ModelSerializer):
    password = PasswordField()

    class Meta:
        model = User
        fields = [
            "id",
            "first_name",
            "last_name",
            "email",
            "password",
        ]

Comments

-1

I know it's an old thread but i got this question today and i like to share my solution here.

You can define your serializer simple and like below:

class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('email', 'username', 'password')
        extra_kwargs = {'password': {'write_only': True}}

on the other hand in your view you can override perform_create method as below:

class UserView(ViewSets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserCreateSerializer

    def perform_create(self , serializer):
        new_user = 
        User.objects.create(username=self.request.data.get("username"))
        new_user.set_password(self.request.data.get("password"))
        serializer.save(password=user.password)

in this way, you can pass extra information to serializer to save.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.