Django: detect user’s first login
Sometimes we want to detect information about user’s first login, e.g. to show account detail or edit form.
First thought would be to look at last_login field in User model, but… it is filled with date after user signed up and doesn’t logged in yet.
So, can we assume that User.last_login and User.date_joined fields have equal value after registration? I think it is too risky - dates might be equal but it is not guaranteed.
In this case we must extend our user profile model (more on this topic: http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users). This is not the cleanest method but the simplest one.
Let’s add new field to out UserProfile model:
class UserProfile(models.Model):
"""Additional user fields"""
user = models.ForeignKey(User, unique=True)
(...)
is_first_login = models.BooleanField(default=True,
verbose_name=_(u"Is first login?"))
Okay, now we need to detect user login and check if it is his first attempt. We will create custom middleware to do the check.
Middleware should be located in settings.py’s MIDDLEWARE_CLASSES after ‘django.contrib.auth.middleware.AuthenticationMiddleware’:
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'users.middleware.FirstLoginMiddleware',
(...)
)
This is FirstLoginMiddleware (e.g. users.middleware.FirstLoginMiddleware):
# -*- coding: utf-8 -*-
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
class FirstLoginMiddleware(object):
def process_request(self, request):
if request.user.is_authenticated() and "dont_check_first_login" \
not in request.session:
request.session["dont_check_first_login"] = True
profile = request.user.get_profile()
if profile.is_first_login:
profile.is_first_login = False
profile.save()
return HttpResponseRedirect(reverse('users:account_edit'))
As you can see, we used session variable named “dont_check_first_login” (long name, isn’t it?).
It is used to determine that user has already logged in so we don’t query database in each request. Consider caching user profile in real life app - this code is example how to catch first login.
Django: How to see if model instance was changed after save (or how to keep model instance state)
There are situations when you want to know when model instance was changed. E.g. slugs generation when you change title (or maybe this example is discussable when comes to SEO?).
SEO matters but there are some real-life situations when you need this - let’s look at following example:
- you’re using django-mptt or some other method to store your document tree,
- URL to your document is generated using all ancestor names like: “Document” with parent “Data” has an URL like this: /data/document/
- you want to rebuild all children URLs when root or any parent document title/slug changes.
Nevertheless, there is some very simple solution to detect model state.
In your models.py, add new property like that:
class ExampleModel(models.Model):
# <<model fields goes here>>
before_save = None
Now, it’s time for signals - we will use pre_save and post_save. First one for getting before save data, second one to recognize it and do some action.
It is easy to detect field value change, e.g. title change generates new slug. See following example:
def object_pre_save(instance, **kwargs):
"""Store object state before save"""
try:
instance.before_save = ExampleModel.objects.get(pk=instance.pk)
except Transaction.DoesNotExist:
instance.before_save = None
def object_post_save(sender, instance, created, **kwargs):
if instance.before_save.title != instance.title:
# <<generate new slug method>>
instance.save()
pre_save.connect(object_pre_save, sender=ExampleModel)
post_save.connect(object_post_save, sender=ExampleModel)
Of course, you can do more complex lookups for change since there is complete “before-save” instance avaible at instance.before_save.
Okay, it is using extra query but if you do it right - e.g. in admin it shouldn’t kill your service. Maybe you have better solution for checking if data has changed? Let us know!
Django: register user with invitation code
We made custom backend for django-registration app allowing you to simplify your service beta testing by require an invitation code from user.
Try it, it’s open source and free to fork and modify!
Remember that generation and distribution of codes is up to you.
Django: the easiest way to run manage commands in crontab
Sometimes there are some management commands I would like to run from crontab at given time or interval. There are some ways when you import setup_environ from Django but there is much simpler solution.
For example - Haystack search index update. Let’s do it in one hour interval.
user@server:~$ crontab -l PYTHONPATH=":/home/www/project/django/lib/python2.5/site-packages" DJANGO_SETTINGS_MODULE=project.settings # m h dom mon dow command 0 * * * * /home/www/project/manage.py update_index
So, all you need is to set PYTHONPATH and DJANGO_SETTINGS_MODULE according to your settings. And the trick is that it can be done in crontab.
Note that this was tested on Debian Linux.
Django: how to mark required form field with *?
If you want to mark required fields with * or some other text/symbol - don’t use some hacks in your python code (Label modify in form class, etc.). Things like that should reside in templates and all you need to do is to apply this:
{% if field.field.required %} <em>*</em>{% endif %}
E.g. form display template:
<form action="." method="post">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<dl>
{% for field in form.visible_fields %}
{% if field.errors %}
<dt> </dt>
<dd>{{ field.errors }}</dd>
{% endif %}
<dt>
{{ field.label_tag }}
{% if field.field.required %} <em>*</em>{% endif %}:
</dt>
<dd>{{ field|safe }}</dd>
{% endfor %}
<dt> </dt>
<dd><input type="submit" value="Submit" /></dd>
</dl>
</form>


