0

I have been trying to figure out how all this validation works, but I am not getting the hang of it. I read the very few examples on djangoproject, but I am missing concepts and how everything is tied together.

If you could please look at my code and rearrange how things should be, as well as a few explanations, that would be awesome!

So I want to do something very simple: have a login from with email ONLY. When a user types their email, i want to check if it's in the database, and if it is, login. if it is not, i want to raise an error 'user already in database' and suggest that this person goes to /register

So what i currently have is:

view.py:

def emailLogin(request, backend, extra_context=None, initial={}):

form = EmailLoginForm(initial=initial)
if request.method == 'POST':
    form = EmailLoginForm(initial=initial, data=request.POST)
    if form.is_valid():
        user = form.do_save()

        _no_pass_login(request, user) # my custom login
        return redirect('/')

    else:
        print ('not valid')

return render_jinja(request, 'registration/email_login_form.html',
        type="register",
        form = form
        )

forms.py:

class EmailLoginForm(forms.Form):
    email = forms.EmailField()
    def do_save(self):
    try:
            u = User.objects.get(email=self.cleaned_data['email'])
        except :
            raise forms.ValidationError("Already in DB")

        return u

So the whole point is that I am missing concepts - where should a validation error be raised, the view or the form? where is it raised to? who catches it? what needs to be imported in each file etc.

This shouldn't be too difficult but i am totally lost now, and i have no examples I can analyze and mod my code to work, so i am here.

2 Answers 2

1

Yes, you do seem to be missing some concepts.

This type of form shouldn't have a save at all. And the whole point of the is_valid() check is to catch the validation errors - so they should be raised by that call. The way to do that is to define clean methods on the form. In this case, since you're only checking the email field, you define a clean_email method. The code should be identical to what you've currently got in do_save.

Now, is_valid() will return False. But there are a couple of tweaks needed in your view to actually show the errors. First, bring that else block back one indent level, so it matches if request.method == 'POST'. Now, instead of that print statement, move the first line - form = EmailLoginForm(initial=initial) in there. Now, when is_valid() is False, the view will fall straight through to the render_to_response with an already-instantiated form containing the validation errors. Magic!

Sign up to request clarification or add additional context in comments.

7 Comments

is the method name related to the field name, or can i use def clean_myemailfunction(self): ?
I think his code will fall through to render_to_response() when the form is not valid already (with the instantiated form and errors). So I don't think your 2nd paragraph is necessary. I agree with your advice in the 1st paragraph.
@mgPePe you have to use clean_<fieldname>. This is all in the documentation on validating forms.
@Brian true, but it's always best to recommend good practice. In this case, the OP is instantiating the form twice for a POST, unnecessarily.
Thanx, and just for reference, shouldn't the form return an email instead of user? Isn't it more 'good practice'. I imagine I should be doing return self.cleaned_data['email'].
|
1

I think this is what Daniel was talking about, but it can be confusing if you don't know exactly what's going on. Basically, all the form does is validate your data. All the saving is done in the view.

view.py

def emailLogin(request, backend, extra_context=None, initial={}):

    form = EmailLoginForm
    if request.method == 'POST':
        form = form(initial=initial, data=request.POST)
        if form.is_valid():
            _no_pass_login(request, user) # my custom login
            return redirect('/')
        else:
            print 'Form not valid'

    else:
        form = form(initial=initial)

return render_jinja(request, 'registration/email_login_form.html',
    type="register",
    form = form
    )

forms.py

class EmailLoginForm(forms.Form):

    email = forms.EmailField()

    def clean_email(self, *args, **kwargs):
        email = self.cleaned_data['email']
        if User.objects.filter(email=email).count() > 0:
            raise ValidationError('User with email "%s" already exists' % email)
        return email

2 Comments

Not quite - the clean_email method should return email, not the whole dictionary.
Good catch. How does the rest look?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.