lofidevops
lofidevops

Reputation: 17002

How can I override username validation in Django 1.11?

I have a custom user model in my Django 1.11 site, along with django-registration.

On my registration form, I prompt for a username and passphrase. I have added MinimumLengthValidator and custom WordCountValidator validation to the passphrase field in settings.py (see below) -- these validation rules are rendered in the registration form automatically.

Now I want to change the username validation with three rules: length, must start with a letter, may only contain alphanumeric characters. I don't mind combining these into a single rule.

I tried adding username_validator to the class and setting that, but nothing happens -- probably because I'm inheriting from AbstractUser not User (related 1.10 bug?).

How can I use my own validation rule (preferably multi-clause) on my username field?

Simplified appearance of form:

Username: [     ]

Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.

Passphrase: [     ]

Your passphrase must contain at least 15 characters.
Passphrase must contain at least three words. Use spaces between words.

Passphrase confirmation: [       ]

Enter the same passphrase as before, for verification.

settings.py

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'OPTIONS': {
            'min_length': 15,
        }
    },
    {
        'NAME': 'custom.validators.WordCountValidator',
        'OPTIONS': {
            'min_words': 3,
        }
    },
]

models.py

class User(AbstractUser):
    objects = UserManager()

    def __init__(self, *args, **kwargs):

        user = super(User, self).__init__(*args, **kwargs)
        return user

    ...

validators.py

class WordCountValidator(object):
    ...

class StartLetterValidator(object):
    ...

class AlphanumericValidator(object):
    ...

class CombinedValidator(object):
    ...

Upvotes: 0

Views: 1233

Answers (1)

Max M
Max M

Reputation: 581

Overwrite the clean() method of your Usermodel and call your validators there:

def clean(self):
    # do some data-clean
    # maybe do a super().clean() here

    validator1 = WordCounterValidator(self)
    validator1.myValidationMethod()
    #...
    validator2 = StartLetterValidator(self)
    validator2.myValidationMethod()
    #...
    validator3 = AlphanumericValidator(self)
    validator3.myValidationMethod()
    #...
    validator4 = CombinedValidator(self)
    validator4.myValidationMethod()
    #...

    # maybe do a super().clean() here

To simplify your validation code, it might be useful to write validation methods instead of validation classes. But I think both designs will do.

Update

Extended answer for the question in comment, due to size of the answer:

django provides ValidationError for this. If you want to raise multiple ValidationErrors at once I suggest to use a dictionary to collect your errors:

err_dict = {}

Then simply add an error to that dict with the field-name as key and the error message as value: err_dict["field-name"] = "Error mssg".

At the end of your clean() simply check your dict for errors with if err_dict (true if error[s] in dict) and raise those with raise ValidationError(err_dict).

In your case you might want to do something like

err_dict = validatot1.myValidationMethod(err_dict)

to extend your err_dict (if necessary) with each validation-function.

Upvotes: 1

Related Questions