Answer a question

I'm coding a login. When I programmed the form by hand I got it working.

The code below works:

views.py

def login_view(request):
    if request.method == 'GET':
        return render(request, 'app/login.htm')
    if request.method == 'POST':
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        user = auth.authenticate(username=username, password=password)
        if user is None:
            return HttpResponseRedirect(reverse('error'))
        if not user.is_active:
            return HttpResponseRedirect(reverse('error'))

        # Correct password, and the user is marked "active"
        auth.login(request, user)
        # Redirect to a success page.
        return HttpResponseRedirect(reverse('home'))

template:

<form method="post" action="{% url 'login'  %}">
    {% csrf_token %}
    <p><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="30" /></p>
    <p><label for="id_password">Password:</label> <input type="password" name="password" id="id_password" /></p>

    <input type="submit" value="Log in" />
    <input type="hidden" name="next" value="" />
</form>

Great! But now I want to do the same thing using Django's forms.

The code below is not working because I get is_valid() == False, always.

views.py:

def login_view(request):
    if request.method == 'POST':
        form = AuthenticationForm(request.POST)
        print form.is_valid(), form.errors, type(form.errors)
        if form.is_valid():
            ## some code....
            return HttpResponseRedirect(reverse('home'))
        else:
            return HttpResponseRedirect(reverse('error'))
    else:
        form = AuthenticationForm()
    return render(request, 'app/login.htm', {'form':form})

template:

<form action="{% url 'login' %}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />

There are a bunch of people on stackoverflow complaining that they get is_valid always false. I have read all those posts, and as far as I can tell I'm not making any of those mistakes. I found a new mistake to make :-)

EDIT: I added a print in the code. The output when opening the login view and submitting is

[27/Dec/2013 14:01:35] "GET /app/login/ HTTP/1.1" 200 910
False  <class 'django.forms.util.ErrorDict'>
[27/Dec/2013 14:01:38] "POST /app/login/ HTTP/1.1" 200 910

and so is_valid() is False, but form.errors is empty.

Answers

It turns out that Maxime was right after all (sorry) - you do need the data parameter:

form = AuthenticationForm(data=request.POST)

The reason for that, though, is that AuthenticationForm overwrites the signature of __init__ to expect the request as the first positional parameter. If you explicitly supply data as a kwarg, it will work.

(You should still leave out the else clause that redirects away on error, though: it's best practice to let the form re-render itself with errors in that case.)

Logo

Python社区为您提供最前沿的新闻资讯和知识内容

更多推荐