【问题标题】:Enforcing lowercase usernames in Django在 Django 中强制使用小写用户名
【发布时间】:2012-08-12 13:49:41
【问题描述】:

目前,在 django.contrib.auth 中,可以有两个用户名为“john”和“John”。我怎样才能防止这种情况发生。

最直接的方法是在 contib.auth.models 中添加一个干净的方法,并在保存之前将其转换为小写,但我不想编辑 contrib.auth 包。

谢谢。

【问题讨论】:

    标签: django


    【解决方案1】:

    收听pre_saveUsers 型号,然后在那里进行检查。最少侵入性和最便携的方式。

    下面是一个示例(改编自用户配置文件示例):

    def username_check(sender, instance, **kwargs):
        if User.objects.filter(username=instance.username.lower()).count():
           raise ValidationError('Duplicate username')
    
    pre_save.connect(username_check, sender=User)
    

    【讨论】:

    • 谢谢!我对信号有点陌生。我可以在哪里放置 pre_save 以确保它运行?我把它放在 models.py 中,但它导致我的 post_save 信号停止工作!使用 pre_save 我得到错误create_user_profile() takes exactly 3 arguments (2 given)。没有预先保存它工作正常。
    • 有些人喜欢将它们放在单独的signals.py 文件中。只要它是可导入的;没关系。
    • 这是次要的,但返回一个 IntegrityError 不是更好吗?这是 Django 当前针对此类错误返回的内容。
    • 这样做的问题是,当用户注册时,他们可能有一个密码管理器,可以保存他们输入的大写或首字母用户名。但是,这会默默地将其小写,因此意味着他们以后无法使用保存的凭据登录。问我怎么知道的!
    【解决方案2】:

    如果您使用 Postgres,则有更好的选择。 Postgres 有一个不区分大小写的字段类型,citext。从 1.11 开始,Django 在django.contrib.postgres.fields.citext 中提供了此功能。您可能还需要处理 url 正则表达式中的大小写敏感问题。

    【讨论】:

      【解决方案3】:

      我可能会在模型上使用用户名的自定义字段来解决这个问题。

      from django.db import models
      
      
      class LowercaseCharField(models.CharField):
          """
          Override CharField to convert to lowercase before saving.
          """
          def to_python(self, value):
              """
              Convert text to lowercase.
              """
              value = super(LowercaseCharField, self).to_python(value)
              # Value can be None so check that it's a string before lowercasing.
              if isinstance(value, str):
                  return value.lower()
              return value
      

      然后在你的模型中..

      from django.contrib.auth.models import AbstractUser
      from django.contrib.auth.validators import UnicodeUsernameValidator
      from django.utils.translation import gettext_lazy as _
      
      # Assuming you saved the above in the same directory in a file called model_fields.py
      from .model_fields import LowercaseCharField
      
      class User(AbstractUser):
          username = LowercaseCharField(
              # Copying this from AbstractUser code
              _('username'),
              max_length=150,
              unique=True,
              help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
              validators=[UnicodeUsernameValidator(),],
              error_messages={
                  'unique': _("A user with that username already exists."),
              },
          )
          # other stuff...
      

      用户名将“自动”全部保存为小写。

      【讨论】:

      • 查看我对上述解决方案的评论...这将导致密码管理器失败。
      • @bjw 不一定,但是是的,这取决于您如何处理用户登录。如果你实现了这个,你还需要实现不区分大小写的登录。幸运的是,如果你使用 django allauth 之类的东西,你可以设置 ACCOUNT_PRESERVE_USERNAME_CASING = False。你也可以只覆盖 Django 用户模型。
      【解决方案4】:

      将接受的答案更新为最新:

      from django.db.models.signals import pre_save
      from django.db.utils import IntegrityError
      from django.dispatch import receiver
      
      @receiver(pre_save, sender=User)
      def username_check(instance, sender, **kwargs):
          """Ensure that username unique constraint is case insensitive"""
          if sender.objects.filter(username__iexact=instance.username.lower()):
              raise IntegrityError("Duplicate username")
      

      【讨论】:

        猜你喜欢
        • 2012-04-25
        • 2015-01-24
        • 1970-01-01
        • 2019-08-14
        • 1970-01-01
        • 1970-01-01
        • 2021-12-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多