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, 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
form.has_errorsis not documented in the 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.errorsin your template is fine.If you tried to access
form.has_errorsin the view, you would get anAttributeError. 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 for more info.To introspect the attributes on the form, use
diron the form object, not the view.However I recommend you explore the form api docs instead.
The csrf token is required when you are using Django’s cross site request forgery protection.