Reputation: 17002
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
Reputation: 581
Overwrite the clean()
method of your User
model 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.
Extended answer for the question in comment, due to size of the answer:
django provides ValidationError for this. If you want to raise multiple ValidationError
s 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