Django REST Framework:强制使用小写用户名

时间:2019-03-18 09:38:58

标签: django django-rest-framework

我刚刚开始使用Django REST Framework作为辅助项目,并且我试图将所有用户名都强制转换为小写字母(因为默认情况下它们区分大小写,并且我不希望人们使用{例如{1}}和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()), ] 发布至少一个用户名和密码来创建新帐户,然后在响应中,他将获得完整的用户对象(包括名字,姓氏,电子邮件和身份验证)令牌)。这行得通。

但是,我正在努力强制使用小写的用户名。例如,当我在序列化程序的create函数中添加类似user/register之类的内容时,尝试创建具有相同用户名(但大小写不同)的用户时,服务器只会生成错误500“ UNIQUE约束失败:auth_user.username” )。那当然不是理想的,错误是500。

我发现了一些添加自定义用户管理器的建议,例如:

validated_data['username'] = validated_data['username'].lower()

但是在通过自定义用户类将其连接并添加到设置文件后,它也没有执行任何操作。我仍然可以使用用户名中的大写字母来创建用户。

最简单的解决方案是什么?

2 个答案:

答案 0 :(得分:4)

如果您使用的是自定义用户模型,并且希望在整个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."),
        },
    )

有一些稍微简单的方法,但是只要您坚持使用ORM,它将通过Django强制执行。祝你好运!

答案 1 :(得分:1)

获得“唯一约束失败:auth_user.username”错误的原因可能是因为用户名验证是在未处理的用户名版本(即大写字母)上运行的,但是在插入时,您试图创建具有用户名的用户转换为小写。例如,假设您在数据库中有一个用户,其用户名如下:

my_username

然后,您尝试使用以下用户名创建用户:

My_Username

这将通过验证,因为数据库中没有用户名“ My_Username ”的用户,但是在创建时,您正在尝试创建用户名“ my_username ”的用户,它存在于数据库中,因此您遇到了IntegrityError。

有很多方法可以解决此问题,您可以在将用户名传递给序列化程序之前对其进行修改,因此在序列化程序上下文中,用户名始终为小写。您也可以像尝试过的那样使用自定义ModelManager,但是在保存之前,需要在管理器中将uesrname转换为小写。无论哪种方式,您都需要使用正确的用户名版本来验证数据,为此,您可以向序列化器添加验证,如下所示:

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