views:

71

answers:

2

Am I doing something wrong, or is this seriously what the developers expect me to write every time I want to check if two fields are the same?

def clean(self):
    data = self.cleaned_data
    if "password1" in data and "password2" in data:
        if data["password1"] != data["password2"]:
            self._errors["password2"] = self.error_class(['Passwords do not match.'])
            del data['password2']    
    return data

And why do I have to validate that the username is unique?

def clean_username(self):
    data = self.cleaned_data['username']
    if User.objects.filter(username=data).exists():
        raise ValidationError('Username already taken.')
    return data

It's a ModelForm. It should already know there's a unique constraint?

A: 

You might want to add an else: part for the first if. Currently the function returns the data without setting any errors even if one of the passwords are absent - is that the intended behavior?

else:
    self._errors["password"] = self.error_class(['One or both of the passwords not found'])

if "password1" in data and "password2" in data: This makes sure that both passwords are present. Without this line, you'll get an error in the next line where you read data[password1] and data[password2] if either of them are not present.

Next three lines compare the passwords and sets the appropriate error message - that's required, isn't it?

As they say, make things as simple as possible, not anymore.

Amarghosh
I don't *think* that's necessary... if either password is absent, that means there's already been an error, doesn't it? I don't really need to throw a second one. And yes, this could get ridiculously simpler. How about when defining the fields, I write `password2 = PasswordField(validate=EqualTo('password1'))`? It should be able to figure out the rest.
Mark
+2  A: 

Firstly, are you seriously complaining about four lines of boiler-plate code? If it really bothers you, create a PasswordForm class that contains that clean logic and sublass it for your own forms as necessary.

Secondly, you don't have to validate unique constraints manually. As you say, the ModelForm does it for you.

Edit after comment

This 'weird syntax' is because checking that two password fields match is a different flow than the normal scheme of things. For a start, you're checking in the main clean method rather than the field-specific clean_myfield. If it had been the latter, you just raise an exception and Django does indeed remove the field data.

So no, this isn't 7 lines on every form - see my note about subclassing - and it certainly isn't 7 lines times multiple fields, because you don't want to do this for any other type of field.

Daniel Roseman
Well something's screwing up somewhere then..because I just got a duplicate key error. I just wanted to bitch a little bit because I'm getting sick of this project :(
Mark
And it's 7 lines... of weird syntax. Why do I have to check if the data is in the dict and then delete it? Isn't that a bit of an odd design? There's already an error list, it can check that if it wants to know if there's been an error. And I should be able to just append another one, without really caring it's already got an error. And then why return data? I'm already manipulating self.cleaned_data, it doesn't really seem necessary to return anything. If they passed me in the dict, then maybe.
Mark
And it isn't even just 7 lines... it's 7 lines on every single freaking form, multiplied by several fields.
Mark
Mark: it should not be 7 lines on every form. Read Daniel's advice and create PasswordForm class where you can store this logic.
Mark van Lent
@Daniel: Well, it has to be in the `clean` method because I'm comparing it to another field, no? And when I say "times multiple fields" I'm not referring specifically to "check if two fields are the same" but any sort of logic that is slightly out of the norm. I'm saying validators like "check unique" and "check if equal" should be built into the framework. Anywho.. that was yesterday. I got it out of my system now. Thank you.
Mark