I want to make a user registration form. Everything works and the user is saved, but his password is not stored. When I see the user page in admin it is in the password field -> "Invalid password format or unknown hashing algorithm.". i use default user mode.
this is my code ->
serializers.py
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'password', )
extra_kwargs = {'password': {'write_only': True},}
def create(self, validated_data):
user = User(
username=validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
views.py
class CreateUser(generics.CreateAPIView):
permission_classes=[AllowAny]
serializer_class=RegisterSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
token, _ = Token.objects.get_or_create(user=user)
return Response({
"user": RegisterSerializer(user, context=self.get_serializer_context()).data,
"token": token.key
})
Related
I'm creating a small app that uses simpleJWT. I want the user to retype their password when registering. Currently, I'm sending data like this
{
"email":"test",
"user_name":"test3",
"password":"b12#wsqp"
}
But what I want to validate is
{
"email":"test",
"user_name":"test3",
"password":"b12#wsqp",
"password2":"b12#wsqp"
}
What i have now is
class CustomUserCreate(APIView):
permission_classes = (AllowAny,)
def post(self, request):
reg_serializer = RegisterUserSerializer(data=request.data)
if reg_serializer.is_valid():
new_user = reg_serializer.save()
if new_user:
return Response(status=status.HTTP_201_CREATED)
return Response(reg_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class RegisterUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email', 'user_name', 'password')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
So my guess is to do
class RegisterUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email', 'user_name', 'password1', 'password2')
extra_kwargs = {'password': {'write_only': True}, 'password2':{'write_only': True}}
def create(self, validated_data):
password1 = validated_data.pop('password1', None)
password2 = validated_data.pop('password2', None)
instance = self.Meta.model(**validated_data)
if password1 is not None and password2 is not None:
if password1 == password2:
instance.set_password(password)
else:
#return some error
instance.save()
return instance
How can I validate if the password are matching?
You can validate the two passwords fields with serializers validate(self, attrs) method like this :
def validate(self, attrs):
if attrs['password1'] != attrs['password2']:
raise serializers.ValidationError({"password": "Password fields didn't match."})
return attrs
in your case change your RegisterUserSerializer class like this :
from rest_framework import serializers
from django.contrib.auth.models import User
from rest_framework.validators import UniqueValidator
from django.contrib.auth.password_validation import validate_password
class RegisterUserSerializer(serializers.ModelSerializer):
password1 = serializers.CharField(write_only=True, validators=[validate_password])
password2 = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ('email','user_name', 'password1', 'password2')
def validate(self, attrs):
if attrs['password1'] != attrs['password2']:
raise serializers.ValidationError({"password": "Password fields didn't match."})
return attrs
def create(self, validated_data):
user = User.objects.create(
username=validated_data['user_name'],
email=validated_data['email'],
)
user.set_password(validated_data['password'])
user.save()
return user
I want to pass the captcha when the user wants to enter his account
If he does not enter the captcha correctly, display the appropriate message
Captcha must be a number and 4 digits
views.py
class LoginApiView(generics.GenericAPIView):
"""login user"""
serializer_class = LoginSerializer
renderer_classes = [CustomizeJSONRenderer]
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)
serializers.py
class LoginSerializer(serializers.ModelSerializer):
username = serializers.CharField(max_length=255)
password = serializers.CharField(max_length=68, min_length=8, write_only=True)
email = serializers.EmailField(max_length=255, min_length=3, read_only=True)
tokens = serializers.CharField(max_length=255, read_only=True)
class Meta:
model=User
fields = ['username', 'password', 'email', 'tokens']
def validate(self, attrs):
username = attrs.get('username', '')
password = attrs['password']
user = authenticate(username=username, password=password)
if not user:
raise exceptions.AuthenticationFailed('Invalid credentials, try again')
if not user.is_active:
raise exceptions.AuthenticationFailed('Account disabled, contact admin')
return {
'username':user.username,
'email': user.email,
'tokens':user.tokens
}
User = get_user_model()
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id','phone' , 'password',)
write_only_fields = ('password',)
def create(self, validated_data):
user = User.objects.create(validated_data['phone'])
user.set_password(validated_data['password'])
user.save()
return user
})
class Register(APIView):
def post(self, request, *args, **kwargs):
phone = request.data.get('phone', False)
password = request.data.get('password', False)
print(phone)
print(password)
if phone and password:
old = PhoneOTP.objects.filter(phone__iexact=phone)
if old.exists():
old = old.first()
validated = old.validate
if validated:
temp_data = {
'phone': phone,
'password': password
}
serializers = CreateUserSerializer(data=temp_data)
serializers.is_valid(raise_exception=True)
user = serializers.save()
old.delete()
return Response({
'status': True,
'detail': 'Account is created '
})
while saving user pasword feild is shows Invalid password format or unknown hashing algorithm.
user is created the password feild is Invalid password format or unknown hashing algorithm.
uable to find y
also tried user.set_unusable_password() in serializer but same result could not figure it out
I try a lot a method you are using. It didn't save the password in the right form.
I suggest you create another model such as Profile and serializers for it and then try this -:
views.py
class Register(APIView):
permission_classes = (AllowAny, )
serializer_class = UserRegistrationSerializer
def post(self, request, *args, **kwargs):
phone = request.data.get('phone' , False)
if phone:
old = PhoneOTP.objects.filter(phone__iexact = phone)
if old.exists():
old = old.last()
validated = old.validated
if validated:
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
response = {
'success' : 'True',
'status code' : status.HTTP_200_OK,
'message': 'User registered successfully',
}
status_code = status.HTTP_200_OK
return Response(response, status=status_code)
else:
return Response({
'status' : False,
'detail' : "OTP haven't verified. FIrst do that step."
})
else:
return Response({
'status' : False,
'detail' : 'Please verify phone number first.'
})
else:
return Response({
'status' : False,
'detail' : 'Phone password, address, Date_Of_Birth, are not sent.'
})
serializers.py
class UserRegistrationSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(required=False)
class Meta:
model = User
fields = ('phone', 'username', 'password', 'profile')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create_user(**validated_data)
users = Profile.objects.create(
user=user,
state=profile_data['state'],
city=profile_data['city'],
date_Of_Birth=profile_data['date_Of_Birth'],
address=profile_data['address']
)
users.save()
return users
Hope the answer is useful
Custom User Model:
class User(AbstractUser):
ROLE_CHOICES = (
('R', 'rider'),
('D', 'driver'),
)
role = models.CharField(max_length=1, choices=ROLE_CHOICES)
phone_number = models.CharField(max_length=10)
cab = models.OneToOneField('Cab', on_delete=models.CASCADE, blank=True, null=True)
Rider serializer:
class RiderSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'phone_number', 'password')
extra_kwargs = {
'password': {'write_only': True}
}
def create(self, validated_data):
username = validated_data.pop('username')
password = validated_data.pop('password')
instance = User(username, **validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
Rider function based view method:
#api_view(['GET', 'POST'])
def rider_list(request):
if request.method == 'GET':
riders = User.objects.filter(role='R')
serializer = RiderSerializer(riders, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = RiderSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save(role='R')
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
rider endpoint: /riders/
I am able to create a user object but user authentication fails as password is getting stored as plain text in object.
I have tried using User.objects.create_user(username, password=password, **validated_data) to set password as hashed value but it does not work
I have also tried using make_password method to set hashed password but nothing seems to work.
Please tell me what am i missing. How do i store the hashed password in password field of custom user object.
create() method should be part of serializer class, not part of Meta:
class RiderSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'phone_number', 'password')
extra_kwargs = {
'password': {'write_only': True}
}
def create(self, validated_data):
password = validated_data.pop('password')
instance = User(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
Also you don't need to pop username field. Just pop password and use it in set_password method.
I have a custom user model as following:
class Librarian(models.Model):
user = models.OneToOneField(User)
phone = models.CharField(max_length=30, blank=True)
# A library has many librarians
which_library = models.ForeignKey('Library', related_name='librarians', on_delete=models.CASCADE)
I have written serializer as following:
class LibrarianSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
email = serializers.CharField(source='user.email')
password = serializers.CharField(source='user.password')
class Meta:
model = Librarian
#fields = '__all__'
fields = ('id', 'username', 'email', 'password', 'phone', 'which_library')
def update(self, instance, validated_data):
instance.user.email = validated_data.get('user.email', instance.user.email)
instance.user.password = validated_data.get('user.password', instance.user.password)
instance.phone = validated_data.get('phone', instance.phone)
instance.which_library = validated_data.get('which_library', instance.which_library)
instance.save()
return instance
def create(self, validated_data):
print('ok')
return Librarian.objects.create(**validated_data)
It's view:
#api_view(['POST'])
def librarian(request, library_id):
"""
Create a new librarian for a specific library
"""
if request.method == 'POST':
print('View')
serializer = LibrarianSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(
serializer.errors, status=status.HTTP_400_BAD_REQUEST)
And I am making a POST request to the corresponding URL with following JSON data:
{
"username": "sample",
"email": "sample#gmail.com",
"password": "12345678",
"phone": "12345",
"which_library": "1"
}
It throws me Cannot assign "{u'username': u'sample', u'password': u'12345678', u'email': u'sample#gmail.com'}": "Librarian.user" must be a "User" instance error.
My goal is to create a Librarian (a user must be automatically created), that's why I am sending username, password, email fields as well. What am I doing wrong?
You need to override create method and create User instance first:
def create(self, validated_data):
user_data = validated_data.pop('user')
user = User.objects.create(**user_data)
user.set_password(user_data['password'])
user.save()
return Librarian.objects.create(user=user, **validated_data)