Невозможно войти в конечную точку токена с именем пользователя/паролем: drf token auth и пользовательская модель пользователя, Django

У меня есть базовое Django приложение, использующее Django rest framework, пользовательскую модель пользователя, наследующую от модели по умолчанию, и базовую аутентификацию токена. Я могу сгенерировать токен для любого пользователя, выполнив команду python3 ./manage.py drf_create_token {USERNAME/EMAIL}, и аутентифицировать с его помощью соответствующие запросы. Однако, когда я пытаюсь обратиться к конечной точке моего токена (в данном случае http://127.0.0.1:8000/api/token/, или эквивалент для развернутого приложения), я получаю

{
    "non_field_errors": [
        "Unable to log in with provided credentials."
    ]
}

Мое тело запроса (application/json) выглядит так:

{
    "username": "test@test.com",
    "password": "test"
}

Я убедился, что пользователь активен; что пароль правильный; и что имя пользователя совпадает с электронной почтой.

Мой пользовательский класс:

class Customer(AbstractUser):
    first_name = models.CharField(max_length=240)
    last_name = models.CharField(max_length=240)
    email = models.EmailField(unique=True)
    phone_number = PhoneNumberField(unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now_add=True)
    is_active=models.BooleanField(default=True)
    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["password", "phone_number", "first_name", "last_name", "username"]

    def __str__(self):
        return f"{self.first_name} {self.last_name}"

релевантные ссылки:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/users/', include('customer.urls')),
    path('api/token/', obtain_auth_token, name="auth_token"),
]

в settings.py у меня есть следующее:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django_extensions',
    'phonenumber_field',
    'customer',
    'contact',
    'rest_framework',
    'rest_framework.authtoken',
]
...
REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
}
...
AUTH_USER_MODEL = 'customer.Customer'
...

Мой сериализатор (здесь контакты представляют собой другую модель):

class CustomerSerializer(serializers.ModelSerializer):

    contacts = serializers.SerializerMethodField()

    def get_contacts(self, obj):
        from contact.serializers import ContactSerializer
        from contact.models import Contact
        return ContactSerializer(Contact.objects.filter(user=obj), many=True, read_only=True).data

    class Meta:
        model = Customer
        fields = [
            'pk', 
            'first_name', 
            'last_name',
            'email', 
            'phone_number', 
            'created_at', 
            'updated_at',
            'contacts',
        ]

Что я могу упустить? Я уже перепробовал все решения здесь: DRF auth_token: "non_field_errors": ["Невозможно войти в систему с предоставленными учетными данными."

Я нашел проблему - следуя https://docs.djangoproject.com/en/4.0/topics/auth/customizing/#a-full-example я смог увидеть, что при использовании пользовательской модели пользователя, вы должны обновить способ создания пользовательских пользователей (через администратора, auth или другим способом), чтобы убедиться, что пароль хэшируется правильно. Следуя этому, я создал пользовательскую форму администратора и пользовательский менеджер пользователей, который правильно переопределяет и обрабатывает сохранение модели:

    def create_user(self, email, first_name, last_name, phone_number, password=None):
        """
        Creates and saves a User with the given email and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
            first_name=first_name,
            last_name=last_name,
            phone_number=phone_number,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user
Вернуться на верх