Django REST Framework: принудительно вводить имя пользователя в нижнем регистре - PullRequest
1 голос
/ 18 марта 2019

Я только начинаю поиграться с Django REST Framework для стороннего проекта, и я пытаюсь заставить все имена пользователей быть строчными (так как по умолчанию они чувствительны к регистру, и я не хочу, чтобы у людей были такие имена пользователей, как kevin и Kevin например).

Это код, который я использую для создания пользователя:

# The serializer
class UserSerializer(serializers.ModelSerializer):
  password = serializers.CharField(write_only=True)
  token = serializers.SerializerMethodField()

  def create(self, validated_data):
    user = get_user_model().objects.create(**validated_data)
    user.set_password(validated_data['password'])
    user.save()
    return user

  def get_token(self, user):
    token = Token.objects.create(user=user)
    return token.key

  class Meta:
    model = get_user_model()
    fields = ('username', 'first_name', 'last_name', 'email', 'password', 'token')


# The View
class RegisterUserView(CreateAPIView):
  model = User
  serializer_class = UserSerializer
  permission_classes = (permissions.AllowAny, )


# And the URL pattern
urlpatterns = [
  path(r'user/register/', RegisterUserView.as_view()),
]

Таким образом, пользователь может создать новую учетную запись, указав по крайней мере имя пользователя и пароль для user/register, и в ответ он получит полный объект пользователя (с именем, фамилией, адресом электронной почты и токеном аутентификации). , Это работает.

Однако я борюсь с принудительным использованием строчных имен пользователей. Например, когда я добавляю что-то вроде validated_data['username'] = validated_data['username'].lower() в функцию создания в сериализаторе, сервер просто генерирует ошибку 500 «Не удалось выполнить ограничение UNIQUE: auth_user.username» при попытке создать пользователя с тем же именем пользователя (но с другим регистром). Это, конечно, не идеально, эта ошибка 500.

Я нашел несколько предложений по добавлению собственного менеджера пользователей, что-то вроде этого:

lass MyUserManager(BaseUserManager):
    def get_by_natural_key(self, username):
        return self.get(username__iexact=username)

Но это тоже ничего не делало, после подключения через пользовательский класс пользователя и добавления в файл настроек. Я все еще могу создавать пользователей с заглавными буквами в имени пользователя.

Какое самое простое решение, чтобы заставить это просто работать?

Ответы [ 2 ]

4 голосов
/ 18 марта 2019

Если вы используете пользовательскую модель пользователя и хотите, чтобы она применялась в Django, вы можете создать собственный валидатор. Например, создайте validators.py в качестве родственного элемента для models.py, который содержит вашу пользовательскую модель пользователя:

from django.core import validators
from django.utils.deconstruct import deconstructible
from django.utils.translation import gettext_lazy as _


@deconstructible
class MyUsernameValidator(validators.RegexValidator):
    """
    Validator for usernames.

    - Only ASCII lowercase letters, numbers and underscore are supported.
    - Must start with a letter.
    """
    regex = r'^[a-z][a-z0-9_]+$'
    message = _(
        'Enter a valid username. This value may contain only lowercase ASCII letters, '
        'numbers, and underscores. Must start with a letter.'
    )
    flags = 0

Затем в вашей пользовательской модели включите:

from .validators import MyUsernameValidator

...

class User(AbstractBaseUser, PermissionsMixin):
    EMAIL_FIELD = 'email'
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = [
        'first_name', 'last_name', 'email',
    ]

    username = models.CharField(
        max_length=16,
        unique=True,
        help_text=_(
            'Required. 16 characters or fewer. Lowercase letters, digits _ only; must start with a letter.'
        ),
        validators=[MyUsernameValidator()],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )

Есть несколько более простых методов, но они будут реализованы через Django, если вы придерживаетесь ORM. Удачи!

1 голос
/ 18 марта 2019

Вероятно, причина того, что вы получаете сообщение об ошибке «УНИКАЛЬНОЕ ограничение: auth_user.username», заключается в том, что проверка имени пользователя запускается на необработанной версии имени пользователя (то есть с заглавными буквами), но при вставке вы пытаетесь создать пользователя с именем пользователя преобразован в нижний регистр В качестве примера, скажем, у вас есть пользователь в базе данных со следующим именем пользователя:

my_username

Затем вы пытаетесь создать пользователя со следующим именем пользователя:

My_Username

Это проходит проверку, потому что в базе данных нет пользователя с именем пользователя " My_Username ", но при создании вы пытаетесь создать пользователя с именем пользователя " my_username ", которое существует в базе данных, поэтому вы получаете IntegrityError.

Существует много способов решения этой проблемы, вы можете изменить имя пользователя перед его передачей в сериализатор, поэтому имя пользователя в контексте сериализатора всегда будет в нижнем регистре. Вы также можете использовать пользовательский ModelManager, как вы уже пробовали, но перед сохранением вам нужно будет преобразовать имя пользователя в строчные буквы в менеджере. В любом случае, вам нужно проверить ваши данные с правильной версией имени пользователя, чтобы сделать это, вы можете добавить проверку в ваш сериализатор следующим образом:

class UserSerializer(serializers.ModelSerializer):
    ...
    validate_username(self, value):
        try:
            get_user_model().objects.get(username=value.lower())
        except ObjectDoesNotExist:
            # Good to go
            pass
        else:
            # Username in use
            raise serializers.ValidationError(...)

        return value
...