integrate django password validators with django rest framework validate_password
Solution 1:
Like you mentioned, when you validate the password
in validate_password
method using UserAttributeSimilarityValidator
validator, you don't have the user
object.
What I suggest that instead of doing field-level validation, you shall perform object-level validation by implementing validate
method on the serializer:
import sys
from django.core import exceptions
import django.contrib.auth.password_validation as validators
class RegisterUserSerializer(serializers.ModelSerializer):
# rest of the code
def validate(self, data):
# here data has all the fields which have validated values
# so we can create a User instance out of it
user = User(**data)
# get the password from the data
password = data.get('password')
errors = dict()
try:
# validate the password and catch the exception
validators.validate_password(password=password, user=User)
# the exception raised here is different than serializers.ValidationError
except exceptions.ValidationError as e:
errors['password'] = list(e.messages)
if errors:
raise serializers.ValidationError(errors)
return super(RegisterUserSerializer, self).validate(data)
Solution 2:
You can access the user object through self.instance
on the serializer object, even when doing field-level validation. Something like this should work:
from django.contrib.auth import password_validation
def validate_password(self, value):
password_validation.validate_password(value, self.instance)
return value
Solution 3:
Use Serializers! Have a validate_fieldname
method!
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'id', 'username', 'password', 'first_name', 'last_name', 'email'
)
extra_kwargs = {
'password': {'write_only': True},
'username': {'read_only': True}
}
def validate_password(self, value):
try:
validate_password(value)
except ValidationError as exc:
raise serializers.ValidationError(str(exc))
return value
def create(self, validated_data):
user = super().create(validated_data)
user.set_password(validated_data['password'])
user.is_active = False
user.save()
return user
def update(self, instance, validated_data):
user = super().update(instance, validated_data)
if 'password' in validated_data:
user.set_password(validated_data['password'])
user.save()
return user