How to find form.has_errors OR form.errors and enable the error in the first place
Question: I have several related questions and post under one topic for clarity's sake.

    
    
    # Django/django_bookmarks/urls.py    
    urlpatterns = patterns('',
        (r'^$', main_page),
        (r'^user/(\w+)/$', user_page),
        (r'^login/$', 'django.contrib.auth.views.login'),
    )    
    
    # login.html
    <html>
      <head>
        <title>Django Bookmarks - User Login</title>
      </head>
    
      <body>
        <h1>User Login</h1>
        {% if form.errors %}
        <p>Your username and password didn't match.
          Please try again.</p>
        {% endif %}
        <form method="post" action=".">
          {% csrf_token %}
          <p><label for="id_username">Username:</label>
        {{ form.username }}</p>
          <p><label for="id_password">Password:</label>
        {{ form.password }}</p>
          <input type="hidden" name="next" value="/" />
          <input type="submit" value="login" />
        </form>
      </body>
    </html>
    

Based on the [book](http://rads.stackoverflow.com/amzn/click/1847196780), the
**login.html** uses `form.has_errors` instead of `form.errors`. However, the
`form.has_errors` doesn't print any warning message even if I enter a wrong
user/password. After some investigation, I change it to `form.errors` and it
works for me.

Question 1> Which one should be used `form.errors` or `form.has_errors`?

Question 2> If `form.has_errors` doesn't work, why django doesn't complain in
the first place. The book was written for Django 1.0 and I am using Django
1.3. Is that the reason?

Question 3> How to check which attributes the form has? I have tried the
following and it doesn't give the information I needed.

    
    
    python manage.py shell
    Python 2.7.1+ (r271:86832, Apr 11 2011, 18:05:24) 
    [GCC 4.5.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> import django.contrib.auth.views
    >>> dir(django.contrib.auth.views)
    ['AuthenticationForm', 'HttpResponseRedirect', 'PasswordChangeForm', 'PasswordResetForm', 'QueryDict', 'REDIRECT_FIELD_NAME', 'RequestContext', 'SetPasswordForm', 'User', '_', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'auth_login', 'auth_logout', 'base36_to_int', 'csrf_protect', 'default_token_generator', 'get_current_site', 'login', 'login_required', 'logout', 'logout_then_login', 'never_cache', 'password_change', 'password_change_done', 'password_reset', 'password_reset_complete', 'password_reset_confirm', 'password_reset_done', 'redirect_to_login', 'render_to_response', 'reverse', 'settings', 'urlparse']
    >>>
    >>> dir(django.contrib.auth.views.login)
    ['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
    

Question 4> When the following statement is needed?

    
    
    {% csrf_token %}
    

Thank you


Answer: `form.has_errors` is not documented in the [forms
api](https://docs.djangoproject.com/en/dev/ref/forms/api/). I did a quick grep
of the source code, and I could not find it in either Django 1.3 or my svn
checkout of the 1.0.X branch. It seems that it's a mistake in the book you are
using.

Checking
[`form.errors`](https://docs.djangoproject.com/en/1.3/ref/forms/api/#django.forms.Form.errors)
in your template is fine. Another option would be to use the
[`is_valid`](https://docs.djangoproject.com/en/1.3/ref/forms/api/#django.forms.Form.is_valid)
method.

    
    
    {% if not form.is_valid %}
    

If you tried to access `form.has_errors` in the view, you would get an
`AttributeError`. However Django does not complain when try to access an
variable that does not exist in the template, so `{{ form.has_errors }}` fails
silently. See the docs on [template
variables](https://docs.djangoproject.com/en/1.7/topics/templates/#variables)
for more info.

To introspect the attributes on the form, use `dir` on the form object, not
the view.

    
    
    >>> from django.contrib.auth.views import AuthenticationForm
    >>> dir(AuthenticationForm)
    

However I recommend you explore the [form
api](https://docs.djangoproject.com/en/dev/ref/forms/api/) docs instead.

The csrf token is required when you are using Django's [cross site request
forgery protection](https://docs.djangoproject.com/en/dev/ref/contrib/csrf/).

