Create your user authentication frontend in django

Django follows the python philosophy “batteries included”, but also tries to be unobtrusive as possible, so while it bundles with a powerful authentication system, it does not provide user registration forms and activation right out of the box, mainly because this is something that each website handles this situation a bit differently from others, but it does offer some tools to get the job done quickly and efficiently.

On this tutorial I’ll show you how you can create your own registration form with email based authentication, and the login / logout functionality. Also, the email messages will be sent in a different thread, so the after registration page can be rendered quickly without having to wait for the email to be delivered.

First thing to do is to start a new project and applications, set up the database, enable the auth contrib package and set up the templates folder(s). It might be useful to enable the admin site as well just for testing purposes. I assume you’re familiar with the process, if not you can take a look at my previous tutorial for a step by step guide. For the purpose of this tutorial, I named the app as my_auth, and added a url pattern in the main project urls.py which redirects all urls starting by accounts/ to the my_auth app. Here’s how it looks:

from django.conf.urls.defaults import *
 
from django.contrib import admin
admin.autodiscover()
 
from django.views.generic.simple import direct_to_template
 
urlpatterns = patterns('',
 
    url(r'^$',  direct_to_template,  {'template': 'base.html'},  name="index"), 
    (r'^admin/', include(admin.site.urls)),
    (r'accounts/',  include('my_auth.register.urls')), 
)

I also created a base.html template (a very basic one), and a url pattern pointing directly to the base template through the direct_to_template generic view. The template just contains a bunch of links so we can navigate between the different parts of the app, and a content block to be overridden by sub templates. Here’s my template:

<html>
    <head>
    </head>
    <body>
        {% block content %}
            <p>Index page</p>
            <p><a href="/accounts/register/">Register</a></p>
            <p><a href="/accounts/login/">Login</a></p>
            <p><a href="/accounts/logout/">Logout</a></p>
        {% endblock %}
    </body>
</html>

The urls in the links are hardcoded, because while we don’t effectively create the views to handle them, if we used the template url tag, every time we try to load a page, django would complain.

Usually the first step in the “authentication workflow” is the registration. We’ll follow along and start by creating the registration page. There is one very basic form (form as in a subclass of django.forms.Form) available through the contrib.auth package, it’s the UserCreationForm. On our first draft we are going to use it unmodified. First step, create a url pattern in the my_auth/urls.py file (you’ll probably have to create the file):

from django.conf.urls.defaults import *
from views import *
 
urlpatterns = patterns('',
    url(r'register/$',  register1,  name="register"), 
)

The register view will serve two purposes, display the registration form itself and process the registration, all through the same url, and we’re going to distinguish both actions by the request method. This is a common procedure on django development. Here’s the view:

from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
 
def register(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            new_user = form.save()
            return HttpResponseRedirect("/")
    else:
        form = UserCreationForm()
 
    return render_to_response("register.html",  {'form': form,  })

If the request method is POST (i.e. the registration form was submitted), we instantiate a UserCreationForm using the POST variables passed in the request, and if the form is valid, we call the save method, which saves the new user to the database, and redirect to the front page.  If the request method is GET (i.e. the url was accessed by a link or written directly in the address bar), we create a plain vanilla UserCreationForm. By the end of the method, unless the form was valid and we were redirected, we should have UserCreationForm stored in the form variable, so we use it to render the registration template:

{% extends "base.django" %}
 
{% block content %}
    <h1>Be a proud member of our super site</h1>
 
    <form action="" method="post">
        {{ form.as_p }}
        <input type="submit" value="Register" />
    </form>
{% endblock %}

This is very simple, we use the method as_p of the django Form class, from which the UserCreationForm inherits, that basically renders the entire form into html. The method name stands for “As P Tags”, so as you may have guessed by now, the form elements will be wrapped in p tags. There are other methods like this one, to render the form as list items or table rows, see the django docs for more info. You can now access your registration page and try to register some users. You can make some errors on purpose; try omitting the username or password, or insert an invalid username or two distinct passwords. See what happen? Courtesy of the forms api… I can read your mind now, and I know what you’re thinking, and yes I agree, we have done nothing special yet, but we’re just starting.

If you never done so, now it’s a perfect opportunity to peek inside the django sources, open the <django source folder>/contrib./auth/forms.py file, you can also see it online here (1.1.x branch), and let’s take a look at the UserCreationForm class definition. As you can see, it’s very simple, it’s a subclass of ModelForm, which is itself a subclass of BaseForm (the mother of all form classes) and is specially suited to build forms that are somewhat tied to a particular mode (if you’re already familiar with the django forms API you can skip the rest of this chapter). The UserCreationForm class defines three properties username, password1 and password2, each is initialized using django form fields, which basically define how we want a particular field presented in the form and then validated. The username property uses a RegexField, probably one of the most useful fields in django forms, it takes a regular expression and validates user input against that regular expression, so when it’s time to work with the values they are already validated for us, in this case we just want alphabet characters, digits and underscores to consider a username as valid. Sweet uh? But don’t start imagining right now how you can use this to validate email addresses, because there is a form field dedicated to that case, as you’re going to see in a moment. The other arguments on the field are pretty straight forward. The Meta subclass defines which model we are tying this ModelForm class and which fields are to be “tied”, so for example, if we reuse this form to allow users to change their settings the password already stored in the database is not displayed. The clean_ methods are used to add some extra validation to our form fields, they are just called if the values pass the first validation provided by form fields itself. Clean_username checks if the username does not exist already, and clean_password2 checks if the value matches the value of password1. We just need to define those methods; django takes care of the rest. Finally, the save method overrides the ModelForm one just to set the password since the meta class instructs that only the username field is to be automatically processed. But notice there is a special argument in the save method signature, commit, which defaults to True.  This UserCreationForm class (just like the ModelForm class) is particularly suited to be subclassed, and we can use the commit argument to specify if we want to save the user right now or not, since we may be calling this save method from a child class save method, and want to perform some more extra work before really saving the user object.

So as you can see, we have two options, either we create a brand new Form class or we just subclass this one. I vote for the second option. So we can start by creating a new file under my_auth folder named forms.py (or whatever you want as long as it uses the .py extension) start typing:

from django.contrib.auth.forms import UserCreationForm
from django import forms
from django.contrib.auth.models import User
 
class RegisterForm(UserCreationForm):
    email = forms.EmailField(label="E-Mail")
 
    class Meta:
        model = User
        fields = ("username", "email", )

We just added an email field, and override the Meta class to make the base ModelForm class aware of the new field. But we need to do a bit more; we need to make sure that there are no duplicate emails in the database as well. So we can create a clean_email method to make this verification:

class RegisterForm(UserCreationForm):
    ...
 
    def clean_email(self):
        email = self.cleaned_data["email"]
 
        try:
            User.objects.get(email=email)
        except User.DoesNotExist:
            return email
 
        raise forms.ValidationError("A user with that email address already exists.")
        ...

Starting to get in shape, we just need to make some changes in the view to use this class instead:

...
from forms import RegisterForm
 
def register1(request):
    if request.method == 'POST':
        form = RegisterForm(request.POST)
        if form.is_valid():
            new_user = form.save()
            return HttpResponseRedirect("/")
    else:
        form = RegisterForm()
 
    return render_to_response("register1.html",  {'form': form,  })

You can start creating some users now. Now, before we take care of validation let’s work on a small issue. If you tested the form you probably noticed that the email field is on the bottom of the form. That usually is not what we want; normally it should appear right bellow the username field. That’s because the order in which the field are shown reflect the order in which the fields are defined. There is not much we can do regarding this, since the email field is defined in a subclass it will always appear after the base class fields. Our only option is to define the correct order in the register template. That is not such a bad thing; it’s probably what you would do anyway. Here’s the new template file:

 {% extends "base.django" %}
 
{% block content %}
    <h1>Be a proud member of our super site</h1>
 
    <form action="" method="post">
        <div>
            {{ form.username.errors }}
            <label for="id_username">Username: </label>
            {{ form.username }}
        </div>
        <div>
            {{ form.email.errors }}
            <label for="id_email">E-Mail: </label>
            {{ form.email }}
        </div>
        <div>
            {{ form.password1.errors }}
            <label for="id_password1">Password: </label>
            {{ form.password1 }}
        </div>
        <div>
            {{ form.password2.errors }}
            <label for="id_password2">Repeat password: </label>
            {{ form.password2 }}
        </div>
        <input type="submit" value="Register" />
    </form>
{% endblock %}

See, is not hard at all, although now the help text does not show, but it’s all available through the form object, you can use form.username.help_text to display it for example.

Ok, now the fun part, we want users to activate their account through email. First thin, we need to setup django to send emails. On your settings.py file you must define EMAIL_HOST, EMAIL_PORT , EMAIL_USE_TLS, EMAIL_HOST_USER and EMAIL_HOST_PASSWORD. Not all are mandatory, if your smtp server uses port 25, you don’t need to specify a port since 25 is the default, id you don’t to authenticate to the server you are not required to define username and password, basically, you just need to define the server, and only if is not localhost (which is the default). Actually for most hosts out there you don’t even need to specify nothing here. But if you’re developing in your home or work computer, is probably best to put something that works here, and python has a great built in server for this (great for testing purposes). If you want to use it, just open a shell and type the following:

python -m smtpd -n -c DebuggingServer localhost:1025

Leave it open, since now all email sent through this simulated server are displayed in the shell. The server uses port 1025 and runs on localhost so you can define your settings like this:

EMAIL_HOST = "localhost"
EMAIL_PORT = 1025

Now we’re prepared to send and receive emails, so let’s start building our validation system. First of all we must make sure that a newly created user is not immediately active. Django user model has a boolean field name is_active, which is true by default. So let’s override the save method in our RegisterForm class:

class RegisterForm(UserCreationForm):
    ...
 
    def save(self):
        user = super(RegisterForm, self).save(commit=False)
        user.is_active = False
 
        user.save()
 
        ...

It’s almost identical to the parent save form, so there’s nothing new here. Now we must create some functions to handle the activation. Usually there’s some sort of activation code, either some random value which is then stored in the database and compared later, or there is some algorithm that builds a code based on user name or email, etc… We are going to do something very simple, we are just going to create an md5 hash against the username. We are also going use a template as the base for the email. So let’s start by creating it:

Hello {{ username }},
    To activate your account follow this url:
    {{ url }}

Now let’s create a file named activation.py or something like that under the my_auth folder. And create a send_activation function:

from django.core.mail import send_mail
from hashlib import md5
from django.template import loader, Context
 
def send_activation(user):
    code = md5(user.username).hexdigest()
    url = "http://127.0.0.1:8000/activate/?user=%s&code=%s" % (user.username,  code)
    print(url)
    template = loader.get_template('registration/activation.html')
    context = Context({
        'username': user.username, 
        'url': url, 
    })
 
    send_mail('Activate account at super site', template.render(context), 'no-reply@example.com', [user.email])

Perefect… And it shouldn’t be hard to understand: we create the code and the url, load the template and create the template context, then we use django send_mail function, which takes the title, body (the rendered template), sender mail, and a list of recipients, in this case it has just a single element, the user email. Now we just need to plug it somewhere, and I guess that the save method of the RegisterForm class would be a perfect place:

...
from activation import send_activation
 
class RegisterForm(UserCreationForm):
    ...
 
    def save(self):
        user = super(RegisterForm, self).save(commit=False)
        user.is_active = False
        send_activation(user)
        user.save()
 
        ...

Try registering a user now. If you’re using a real mail server you must use a valid email address as well, so you can test it, but if you’re using the fake python server, just use any email you want, you can even use Obama’s email and pretend that he just registered on your site ;-) . But there’s something you should know when using the fake mail server, it might show some extra character that are not supposed to be there, so the validation code might not be valid. You can use a print statement after you define the url to print it to the same console as the development server, so you can use it later.

But imagine the following situation. Someone decides to register on your site, he fills the registration form and submit it. Meanwhile, back on your server, it processes the request and sends the activation email, but the mail server is too busy to process your request as fast as you would like, especially if the mail server is on a different machine than the web server. What happens is that your new user won’t get a response until the email is sent. This is the same if for example you have to do some heavy database operations, but luckily, python has thread support, so you can send your email for example using a different process while the main process continues to handle the http response. And is not that hard as it might look, take a look at the new “threaded” save method:

...
from threading import Thread
 
class RegisterForm(UserCreationForm):
    ...
 
    def save(self):
        user = super(RegisterForm, self).save(commit=False)
        user.is_active = False
 
        thread = Thread(target=send_activation,  args=[user])
        thread.setDaemon(True)
        thread.start()
 
        user.save()
 
        ...

See, couldn’t be simpler. The thread “constructor” takes the function and a list of arguments to pass on to the function, then we call setDaemon to true, otherwise it wouldn’t work, and start the thread, then we continue happily with what we’re doing before, while the send_activation function does its job in a different process.  You can make it “sleep” for a while using python time module to to simulate a busy server:

...
import time
 
def send_activation(user):
    time.sleep(10)
    code = md5(user.username).hexdigest()
    ...

Now try to register a user, the response should be almost immediate, but your email should take 10 seconds to be sent. Nice uh?

Now is time to create a view to process the activation. First let’s create a function to do this, it should get the username and the activation code as arguments and live in the same file as send_activation:

from django.contrib.auth.models import User
...
 
def activate_user(username,  code):
    if code == md5(username).hexdigest():
        user = User.objects.get(username=username)
        user.is_active = True
        user.save()
        return True
    else:
        return False

Simple, we just check the code against an md5 hash based on the username, just like we did to generate it in send_activation, and if that test succeeds we retrieve the user from the database and activate it. Then we return True to flag the success of the operation, or false if the check fails. Notice that ideally we should check if the user really exists as well, but for the purpose of this tutorial we’ll leave it this way.  Now let’s create the url pattern:

urlpatterns = patterns('',
    ...
    url(r'activate/$',  activate,  name="activate"), 
)

And the view:

from activation import activate_user
from django.http import HttpResponseRedirect, Http404
...
 
def activate(request):
    user = request.GET.get('user')
    code = request.GET.get('code')
 
    if activate_user(user,  code):
        return HttpResponseRedirect("/")
    else:
        raise Http404

Again, this is very basic, we get the username and the code from the GET variables, and in case the activation succeeds we redirect the user to the front page, otherwise we raise an Http404 exception, which displays a 404 error page.

Now that we’ve created and activated some users is time to allow them to login and logout. This is the simplest part of all. We’ll use some bundled views to achieve that, we just need to create a simple template to display the login form. This template will receive a Form object in the context, and by default django expects it to live in registration/login.html (but we can change that), so we can do just this:

{% extends "base.django" %}
 
{% block content %}
    {% if form.errors %}
        <p class="error">Oops, invalid username or password</p>
    {% endif %}
 
    <form action="{% url login %}?next=/" method="post">
        {{ form.as_p }}
        <input type="submit" value="login" />
    </form>
{% endblock %}

The only tricky part is the form action url. We can use a next GET variable to tell django where to redirect the user id the login succeeds, in this case the index page, otherwise it will just use the default which is /accounts/profile/. The rest is old stuff by now.

Now we just need to define the url pattern, and since we’re here we can define the pattern for the logout page as well:

...
from django.contrib.auth.views import login, logout
 
urlpatterns = patterns('',
    ...
    url(r'logout/$',  logout,  name="logout"), 
    url(r'activate/$',  activate,  name="activate"), 
)

Now just go to the base template and add a next GET variable to the logout url as well.

            <p><a href="/accounts/logout/?next=/">Logout</a></p>

And that’s pretty much it. Now you should be able to create your own authentication frontend easily.

Hope you like this tutorial.

Cheers



Add computed default arguments to python functions or methods

Luckily, I’ve been working with python in my last project. I say luckily because python is a language I happen to love.

In this project I had some repetitive code that I hate and goes against many programming philosophies. The problem was with some functions and methods with a couple of arguments that had computed defaults. In my particular case the defaults where current timestamps or value that needed to be retrieved by the database. So I’ve managed to find a great solution for that, using the power of introspection and a feature available since 2.4, decorators.

If you don’t know what decorators are, here’s a quick brief. Decorators are mainly syntactic sugar, that allows us to specify that a given function or method needs to be transformed by other function after it’s creation. There was a lot of discussion around the syntax to use in this new feature, see this PEP, but I think the right decision was taken, since it makes the code more clear.

So the idea behind my solution is that for each function that takes a computed default, we can use a callable as the default, and then the decorated version of the function checks first if that argument was passed, otherwise it computes it using the callable default. Here’s my first draft:

import inspect
 
def dynargs(fn):
    def decorated(*args, **kwargs):
        (argnames, varargs, keywords, defaults) = inspect.getargspec(fn)
        strip = max(len(args), len(argnames) - len(defaults))
 
        for name, default in zip(argnames[strip:], defaults):
            if callable(default) and not name in kwargs:
                kwargs[name] = default()
 
        return fn(*args, **kwargs)
 
    return decorated

The inspect.getargspec function retrieves all there is to know about the function arguments.  Next, we check how many arguments we want to strip out of the list, either the total non named args, because the argument we want to parsed may have been passed as a positional argument, or all the arguments with default values.

The for loop then iterates on a generated list of tuples with name / default pairs (almost like a dictionary), and if the default is callable and it was not passed as a named argument, we add it to the dictionary of named arguments. Here’s a small test:

import datetime
 
@dynargs
def test_func(d=datetime.datetime.now):
    print(d)
 
if __name__ == "__main__":
    import time
    test_func()
    time.sleep(2)
    test_func()
 
#output
#2010-01-14 11:48:43.982000
#2010-01-14 11:48:45.982000

As expected, each call to the test function prints the time at the function call. But as any hack we must be concerned with performance. So I ran a small timeit test:

import datetime
 
@dynargs
def test_func(d=datetime.datetime.now):
    pass
 
def test_func1(d=None):
    if d is None:
        d = datetime.datetime.now()
 
if __name__ == "__main__":
    import timeit
    t = timeit.Timer("test_func()", "from dynargs import test_func")
    print("test_func: %f seconds" % (t.timeit(100000)))
 
    t = timeit.Timer("test_func1()", "from dynargs import test_func1")
    print("test_func1: %f seconds" % (t.timeit(100000)))
 
#output
#test_func: 2.273624 seconds
#test_func1: 0.347172 seconds

As you can see, this first draft can be a real performance killer if you happen to call that particular function a good amount of times through the life cycle of the script. So I decided to try a more elegant solution, which is to create an à la carte decorated function:

import inspect
 
def dynargs(fn):
    (argnames, varargs, keywords, defaults) = inspect.getargspec(fn)
 
    callables = [
        (name, index + 1, default) for ((index, name), default)
        in zip(enumerate(argnames[-len(defaults):]), defaults)
        if callable(default)
    ]
 
    def decorated(*args, **kwargs):
        for name, default in [(name, default) for (name, index, default)
                                in callables if index &gt; len(args) and not name in kwargs]:
            kwargs[name] = default()
 
        return fn(*args, **kwargs)
 
    return decorated

Looks weird because it as some complicated list comprehensions here (I love python list comprehensions), but is not hard to understand. Callables becomes a list of tuples in the form of containing each the name, index position on the argument list and obviously, the callable default. Then the decorated function adds all non-passed arguments in the callables list if their indexes are higher than the number of element on the passed positional arguments list and are not passed as named arguments.  Now all the introspection is made at compile time and not at run time. A new timeit test shows the following results:

#output
#test_func: 0.588709 seconds
#test_func1: 0.312928 seconds

That’s way better, but this is a very generic decorator, and can get even better if you adapt it to your particular situation, for example, you may not need the index of each callable default if you know in advance that you are going to use only named arguments when calling functions decorated by dynargs, thus you can skip some computations.

Now let’s play with this a bit. We know that python decorators can be a call to a function that returns another decorator. Let’s imagine the following situation, we have a couple of functions that have arguments that if not present should be pulled out of a database for example. We can create a decorator for this specific case:

import inspect
 
def get_that_setting(name):
    return "setting is %s" % name
 
def db_setting(argname, setting):
    def decorator(fn):
        index = [index for (index, name) in enumerate(inspect.getargspec(fn)[0]) if name == argname][0]
 
        def decorated(*args, **kwargs):
            if index &gt; len(args) - 1 and not argname in kwargs:
                kwargs[argname] = get_that_setting(setting)
 
            return fn(*args, **kwargs)
 
        return decorated
 
    return decorator
 
@db_setting("some_setting", "name_ind_db")
def test_func(some_setting):
    print(some_setting)
 
if __name__ == "__main__":
    test_func()
    test_func("cool")
 
#output
#setting is name_ind_db
#cool

The call to db_setting returns a decorator, which calculates the index of argname in the list of arguments of the function to be decorated. The rest works just like the previous example, if the argument was not passed as a positional or named argument, it’s just added to the named arguments list. When defining the test function we don’t even need to provide a default value in this case.  This was just a silly example, but I think you get the idea.

Cheers