diff --git a/rest_framework/authtoken/serializers.py b/rest_framework/authtoken/serializers.py index 63e64d6683..477fc864f6 100644 --- a/rest_framework/authtoken/serializers.py +++ b/rest_framework/authtoken/serializers.py @@ -1,4 +1,4 @@ -from django.contrib.auth import authenticate +from django.contrib.auth import authenticate, get_user_model from django.utils.translation import gettext_lazy as _ from rest_framework import serializers @@ -20,13 +20,33 @@ class AuthTokenSerializer(serializers.Serializer): read_only=True ) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + User = get_user_model() + username_field = User.USERNAME_FIELD + if username_field != 'username' and 'username' in self.fields: + # Rebuild the fields mapping to preserve the original position + # of the login field when renaming it. + original_items = list(self.fields.items()) + new_fields = self.fields.__class__(self) + for name, field in original_items: + if name == 'username': + name = username_field + field.label = _(username_field.capitalize()) + new_fields[name] = field + self.fields = new_fields + def validate(self, attrs): - username = attrs.get('username') + User = get_user_model() + username_field = User.USERNAME_FIELD + username = attrs.get(username_field) password = attrs.get('password') if username and password: - user = authenticate(request=self.context.get('request'), - username=username, password=password) + user = authenticate( + request=self.context.get('request'), + **{username_field: username, 'password': password} + ) # The authenticate call simply returns None for is_active=False # users. (Assuming the default ModelBackend authentication @@ -35,7 +55,7 @@ def validate(self, attrs): msg = _('Unable to log in with provided credentials.') raise serializers.ValidationError(msg, code='authorization') else: - msg = _('Must include "username" and "password".') + msg = _(f'Must include "{username_field}" and "password".') raise serializers.ValidationError(msg, code='authorization') attrs['user'] = user