Remembering Django form submissions when authenticating
If you play around with the built-in Django login mechanism, you might notice that it has one very useful feature: if your session ends before you submit a form, it will save your form data while you log in, and it lets you know this so that you don’t panic.
Django does this by saving the actual POST dictionary into the form. It encodes it using a special function that pickles it and turns it into an ASCII representation that can be stored in a form.
If we take the line “return render_to_response("cms/login.html", context)” from the authenticate method on the authenticator object and replace it with “return self.login_form(context)”, we can make a smarter login form.
[toggle code]
- from django.contrib.admin.views.decorators import _encode_post_data
- …
-
def login_form(self, context):
- request = self.request
-
if request.POST and 'post_data' in request.POST:
- # User has failed login BUT has previously saved post data.
- post_data = request.POST['post_data']
-
elif request.POST and not 'login_submission' in request.POST:
- # User's session must have expired; save their post data.
- post_data = _encode_post_data(request.POST)
-
else:
- post_data = None
- context['post_data'] = post_data
- return render_to_response("cms/login.html", context)
There are three cases to check for here: the person is just logging in; the person is logging in after attempting to submit a form; and the person is logging in after mistyping their username or password after attempting to submit a form. And we need to be able to tell the difference between submitting a form that has data worth keeping, and submitting the login form.
For the latter, I added a hidden “login_submission” field to the form. So the logic is this:
- If there is POST data and there is a “post_data” field, keep it.
- If there is POST data and there is no “login_submission” field, save the POST data in post_data.
- Otherwise, don’t save any POST data.
Saving the POST data is performed by first encoding the POST dictionary and then adding the encoded POST dictionary to the form’s context before rendering the form template. Django already has an encoding (and decoding) function in django.contrib.admin.views.decorators, as _encode_post_data and _decode_post_data.
So the next step is to update the form template to keep this information:
[toggle code]
-
<form action="{{ action_url }}" method="post">
-
{% if post_data %}
- <h2>Your session has expired. Please log in again to save your data:</h2>
- <input type="hidden" name="post_data" value="{{ post_data }}" />
-
{% else %}
- <h2>Please log in to the test CMS:</h2>
- {% endif %}
-
<table>
- {{ form }}
- </table>
- <input type="hidden" name="login_submission" value="1" />
- <input type="submit" value="Log In" />
-
{% if post_data %}
- </form>
The form displays a different message if there is POST data being stored in it.
In the form object in the view, we can use _decode_post_data to get the POST dictionary back:
[toggle code]
-
if 'post_data' in self.request.POST:
- post_data = _decode_post_data(self.request.POST['post_data'])
And from there it can be treated as if it were taken directly from request.POST.
In response to Custom authentication in Django: Decorators can be used to restrict access to any view.
- Django
- “Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design.” Oh, the sweet smell of pragmatism.
More Django
- Converting an existing Django model to Django-MPTT
- Using a SQL database to mimic a filesystem will, eventually, create bottlenecks when it comes to traversing the filesystem. One solution is modified preordered tree traversal, which saves the tree structure in an easily-used manner inside the model.
- Two search bookmarklets for Django
- Bookmarklets—JavaScript code in a bookmark—can make working with big Django databases much easier.
- Fixing Django’s feed generator without hacking Django
- It looks like it’s going to be a while before the RSS feed generator in Django is going to get fixed, so I looked into subclassing as a way of getting a working guid in my Django RSS feeds.
- ModelForms and FormViews
- This is just a notice because when I did a search, nothing came up. Don’t use ModelForm with FormView, use UpdateView instead.
- Django: fix_ampersands and abbreviations
- The fix_ampersands filter will miss some cases where ampersands need to be replaced.
- 29 more pages with the topic Django, and other related pages