To add the confirm_password field when registering a new user, the simplest way seems to be to define another serializer RegisterUserSerializer that inherits the UserSerializer:
class RegisterUserSerializer(UserSerializer): '''Serializer for registering a new user''' confirm_password = serializers.CharField( style={'input_type': 'password'}, write_only=True ) def validate(self, data): '''Validate that password and confirm_password are the same''' if not data['password'] == data['confirm_password']: raise serializers.ValidationError('Passwords are not matching.') return data class Meta(UserSerializer.Meta): model = User fields = ['username', 'password', 'confirm_password', 'is_active']
A new field confirm_password has been defined along with a validate method that performs object level checking on the serializer to ensure that the password and confirm_password field are identical. The view method will now use request.data to create a RegisterUserSerializer instance instead of UserSerializer. The only problem is that the error for passwords not matching is not very nice – “non_field_errors – Passwords not matching”. This is because errors found on the object using the validate method are sent out in the dictionary with non_field_errors key. This means that the error messages will need to be customized rather than processed in the view method.
class Meta: model = User fields = ['username', 'password', 'is_active'] read_only_fields = ['is_active', ] extra_kwargs = { 'username': { 'error_messages': { 'blank': 'The username field is required', 'required': 'The username field is required' } } }
I included both blank and required error messages for the browser form as well as an API request sent from Postman. The password fields can have similar error messages in their serializer field definitions.
password = serializers.CharField( style={'input_type': 'password'}, write_only=True, error_messages={ 'blank': 'The password field is required', 'required': 'The password field is required' } ) confirm_password = serializers.CharField( style={'input_type': 'password'}, write_only=True, error_messages={ 'blank': 'The confirm password field is required', 'required': 'The confirm password field is required' } )
The tests for the API endpoint can be updated:
def test_register_new_user(): '''Test API to register new user''' client = APIClient() # Should result in a user created in db api_response = client.post( '/user/register-user', { 'username': 'someuser@domain.com', 'password': 'somepass', 'confirm_password': 'somepass' }, format='json' ) assert api_response.status_code == 201 assert api_response.data['username'] == 'someuser@domain.com' assert hasattr(api_response.data, 'password') == False assert api_response.data['is_active'] == False users_in_db = User.objects.all().count() assert users_in_db == 1 # Should fail model validation api_response = client.post( '/user/register-user', { 'username': 'someuser', 'password': 'somepass' }, format='json' ) assert api_response.status_code == 400 # Should fail because of missing password field api_response = client.post( '/user/register-user', { 'username': 'someuser@domain.com', }, format='json' ) assert api_response.status_code == 400 # Should fail because of missing username field api_response = client.post( '/user/register-user', { 'password': 'somepass', }, format='json' ) assert api_response.status_code == 400 # Should fail become of missing username and password api_response = client.post( '/user/register-user', format='json' ) assert api_response.status_code == 400 # Should fail because of missing confirm_password field api_response = client.post( '/user/register-user', { 'username': 'someuser@domain.com', 'password': 'somepass', }, format='json' ) assert api_response.status_code == 400 # Should fail because the passwords do not match api_response = client.post( '/user/register-user', { 'username': 'someuser1@domain.com', 'password': 'somepass', 'confirm_password': 'somepass1' }, format='json' ) assert api_response.status_code == 400 users_in_db = User.objects.all().count() assert users_in_db == 1
No comments:
Post a Comment