[Django]-How can I allow spaces in a Django username regex?

3👍

If you aren’t trying to modify the fields on the default User class, the other Jonathan’s answer for post 1.10 is good except for a couple small mistakes.

  • username_validator = MyValidator needs to be username_validator = MyValidator() or the validator will fail silently and allow anything.
  • The dash should be the last character in the brackets or escaped (otherwise it will act as a range).
  • A space should be used instead of the \s character, which would allow any whitespace (including tabs and newlines).

The final code looks like:

from django.contrib.auth.models import User
from django.contrib.auth.validators import UnicodeUsernameValidator

class MyValidator(UnicodeUsernameValidator):
    regex = r'^[\w.@+\- ]+$'

class MyUser(User):
    username_validator = MyValidator()

    class Meta:
        proxy = True  # If no new field is added.

(simply replace UnicodeUsernameValidator with ASCIIUsernameValidator if using Python 2). Note that the dot is within brackets, so it doesn’t need to be escaped.

If you are modifying the fields on your User class, you are probably subclassing AbstractUser and you can’t use proxy = True. This means the username field on AbstractUser will use the username_validator declared on AbstractUser, not yours. To fix this, you pretty much have to re-declare username on your model, like so:

from django.contrib.auth.models import AbstractUser
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.utils.translation import ugettext_lazy as _    

class MyValidator(UnicodeUsernameValidator):
    regex = r'^[\w.@+\- ]+$'

class MyUser(AbstractUser):
    username_validator = MyValidator()
    username = models.CharField(
        _('username'),
        max_length=150,
        unique=True,
        help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
        validators=[username_validator],
            error_messages={
            'unique': _("A user with that username already exists."),
        },
    )

Make sure you run makemigrations and migrate afterwards.

I’ve tried a number of ways to change the validators on username after it has already been declared, but haven’t had any luck, so it looks like this is the best way for now.

1👍

You’ll need to modify the user where the validator exists. The following code should work for Django 1.9.

With this user below you should be able to use MyUser instead of User for the form that you wrote.

from django.contrib.auth.models import AbstractUser
from django.core import validators

class MyUser(AbstractUser):
    validators=[
                validators.RegexValidator(
                    r'^[\w.@+-\s]+$',
                    _('Enter a valid username. This value may contain only '
                      'letters, numbers, spaces ' 'and @/./+/-/_ characters.')
                ),
            ],

    class Meta:
        proxy = True  # If no new field is added.

If you want to do it in Django 1.10 you’ll have to change the code slightly. In Django 1.10 a new property was added username_validator and you’ll have to override that. You can read more about it in the manual.

If you’re using python2 you’ll have to override ASCIIUsernameValidator or if you using python3 you’ll have to override UnicodeUsernameValidator. For simplicity I’ll assume that you’re using python3. You can see the source code of the validation here.

from django.contrib.auth.models import User
from django.contrib.auth.validators import UnicodeUsernameValidator

class MyValidator(UnicodeUsernameValidator):
    regex = r'^[\w.@+-\s]+$'

class MyUser(User):
    username_validator = MyValidator

    class Meta:
        proxy = True  # If no new field is added.

Leave a comment