Hello, I am Antoliny . I am currently working on the issue related to ticket #35693. PR.
This issue highlights the consistency problem between password validators and general field validators.
However, I think that while the role of general validators and password validators is the same, they are different types due to the difference in how they are called and the fact that password validators have an additional user parameter.
Iām not sure if itās correct to modify the password validators to maintain consistency in this regard. Even if we were to add the __call__ and __eq__ magic methods to ensure consistency, Iām not sure they would be useful.
Iām curious to know what Django community think about this.
How about using the term āpassword validatorā instead of āvalidatorā to clarify the difference between password validators and general validators in the password validation documentation?
I think youāre correct that theyāre different types, that serve different purposes. And also that the names should reflect that. What are the current names, and what namespaces are they in, and what might you suggest changing them to? Often I find that Iām ok with a less specific name as long as its in an appropriate namespace so that it isnāt ambiguous in context.
If we conclude that it is clear that field validators and password validators are different things and we donāt expect them to have the same behavior - we can also wontfix the ticket
I havenāt been able to track down why they didnāt just make it __call__ in the first place, with user being an optional argument. If we can track that down, I think it would really help us to understand what to do. Itās possible that there was no particular reason, perhaps it pre-dated inclination to override the __call__ method generally.
One thing Iāve not got my head around is why these password validators are expected to pass silently if the user isnāt given when they need a user to do their validation. Iām not sure whether or not thatās the most appropriate behavior for general field validators, as I tend to prefer raising loud errors when I use a function in the wrong place. If that intuition is right, then it might mean that the __call__ method is appropriate, but perhaps needs slightly different behavior than validate!
Based on what Iāve figured out so far, Iām mildly in favor of adding the __call__ and __eq__ methods to make these usable as general validators, but using a password validator as a validator isnāt difficult:
Thank you for the great opinion. @ryanhiebert
I was also curious as to why the __call__ method wasnāt used initially to implement the Field Validator approach, but I think I found some of the reasons through the links in ryanhiebertās comment.
According to Erik Romihn, the reason for not using standard Django validators for the password validator was because they didnāt provide sufficient flexibility and configurability.
In my opinion, since the password validator is closely related to the user and login, there are cases where it needs to validate user attributes, such as with the UserAttributeSimilarityValidator. This might be one of the reasons why the current password validator was designed this way.
I agree with the point that using the password validator as a validator is not difficult in its current form. However, if methods like __call__ were added, it would allow access in the same way as standard validators, making it easier for users to approach with a more consistent usage.
That explains why they needed classes instead of just functions, but not why they didnāt use the __call__ method to implement it. I suspect that they probably just didnāt think about doing that.
Given my concerns about password validators that require a user to process not raising errors (by design), my suggestion is to add a __call__ method only to the password validators that do not need the user to be passed in. Iād think that there shouldnāt be any optional arguments to the __call__ method when implemented to conform to the normal protocol for validators.
I think all password validators, except for UserAttributeSimilarityValidator, can be used as general purpose validators.
In particular, MinimumLengthValidator is functionally identical to MinLengthValidator and MaxLengthValidator in the standard validators (itās closer to a customized version of MinLengthValidator for passwords).
Also, I believe that NumericPasswordValidator can be effectively used in scenarios beyond just password validation.
I consider my skills to be lacking and think Djangoās password validation logic is excellently and beautifully designed. However, I struggle to understand the decision to design password validation using AUTH_PASSWORD_VALIDATORS in settings.py. I believe this could have been sufficiently handled using general Field and Validator functionality.
Of course, compared to the developers of Django, my perspective might seem like that of a beginner, which could explain my impression.
By default validating fields use this syntax validator(value) but password validators donāt implement .__call__(). Therefore making them unusable outside of validate_password().
As @ryanhiebert pointed out, these are not āunusable outside validate_password()ā as they can be used with CharField(..., validators=[MinimumLengthValidator().validate]).
Those that need a user will pass silently (adding a __call__ doesnāt change that).
So I think the problem this wanted to solve āmake them usable outside validate_password()ā is not a valid problem.
That doesnāt mean we couldnāt change the design of these.
As @Antoliny0919 mentioned, thereās some potential refactoring we can do with MinimumLengthValidator being functionally MinLengthValidator.
So in short, I think the original ticket (add __call__ to password validators so they are usable outside the validate_password context) is a wontfix and once we have an agreement on āwhere do we want to end upā with validators and password validators - then we can make steps in that direction
I think it has a much better direction and states the current design quirks
I donāt think weāre ready to work on this until is has been discussed more.
The main question mark I had from the ticket is what this means for the setting AUTH_PASSWORD_VALIDATORS (which has no split between ones that need a user and do not need a user).
Bare in mind folks can have written their own password validators which would need migrating to a new format.
I think:
what would be the end state
how could folks customize it
what would be the migration path
This has been around soooo long, and almost certainly will include breaking changes. So I am even tempted for this to consider a DEP or certainly needs more input than what we have right now.
If we mess up password validation during the migration process, that would not be good, so we need to tread carefully and really consider whether the end state is worth the migration.