1
votes

I've got a Django form class, that inherits from the built-in UserCreationForm.

I'm working on submitting the form using AJAX, and returning the bound form (including errors) as rendered HTML if it doesn't validate.

Something puzzling me is that the errors relating to the password (e.g. too short, common password...) appear for the password2 / confirmation field. Here's a screenshot of the default behaviour: enter image description here

From a UX perspective I feel as though it would be more useful for the errors to appear for the first password field in the form, so users can adjust that one, then confirm it by typing it again below.

I've noticed that in UserCreationForm, clean_password2(), doesn't actually validate the password, it just checks that password1 and password2 match. Then in the _post_clean() method, password2 is validated, and any errors are added to that field.

In my attempt to change it, I have overridden _post_clean() as follows:

def _post_clean(self):
    super(forms.ModelForm, self)._post_clean()
    password = self.cleaned_data.get('password1')
    if password:
        try:
            password_validation.validate_password(password, self.instance)
        except forms.ValidationError as error:
            self.add_error('password1', error)

I don't want to call super, and have it validate and send errors to password2, so I am calling the post_clean method of the grandparent (ModelForm) instead (I think!), to not suffer consequences of leaving anything that does out. Then validating and sending errors to password1 instead.

This is the post_clean() method for UserCreationForm for comparison:

def _post_clean(self):
    super()._post_clean()
    # Validate the password after self.instance is updated with form data
    # by super().
    password = self.cleaned_data.get('password2')
    if password:
        try:
            password_validation.validate_password(password, self.instance)
        except ValidationError as error:
            self.add_error('password2', error)

On the surface this seems to work the way I want it to, but I am not very confident when it comes to overriding methods – I'm scared there will be weird side effects.

So my question is, is this ok? And do you know what I mean about wanting to show the errors for password1 instead? Any advice would be much appreciated!

1
Have you tried your solution? What you have got? Errors? Unexpected behavior?JPG
Yep I have, and it seems to work, I just wanted to get other opinions and advice - sometimes there can be problems you don't notice on the surface/initially.Ffion

1 Answers

2
votes
  • When you want to override a method, it's good to see the documentation for the method that you want to override.
  • In most cases when overriding the default methods, *args, **kwargs will have higher affect.

In major cases, we have to make sure while overriding methods which take args and kwargs.Most common error is arguments mismatch. *args (arguments, ex: def function(1,2,3)) and **kwargs (keyword arguments, ex: def function(name='sam', age=25)) are the dynamic parameters to the function. When you define function without *args, **kwargs it has a fixed number of inputs which means it cannot accept more (or less) than you defined in the function. *args is a tuple and **kwargs is a dictionary. Here, Read more about *args and **kwargs.

It is also important that the order of doing things as it may have side affects or errors. Anyway it depends on the method.

Think this way:

  • You are overriding UserCreationForm, Django default registration form. This will affect wherever registration is used.
  • _post_clean(self) belongs to UserCreationForm which will affect wherever django registration is used.

Q. How your edits will affect the default behaviour?

A. You are changing the password validation (just changing the fontend behaviour). No matter whether it is password1 or password2, it won't affect anything because both passwords will be matched and sent to backend. So yes, it is completely ok in this scenario. Self will reffer to UserCreationForm, so it won't affect other ModelForm instances.