Django Registration

August 26, 2011

I'm using django-registration and I wanted to add a checkbox to the registration form which would indicate whether the user registering was a teacher or not. This value would then be stored on the user profile.

I took the opportunity to work out how to do this without modifying the provided django-registration source code.

urls.py

I copied in the contents of url.py from django-registration (registration/backends/default/urls.py) into my main project's urls.py file. At the same time I passed a new form into the /accounts/register endpoint, and I also referred to a local view for this functionality, rather than using the one supplied with django-registration:

from progperc.users.views import register

url(r'^accounts/register/$', register,
                       { 'backend': 'registration.backends.default.DefaultBackend',
                         'form_class' : RegistrationForm },
                         name='registration_register'),

forms.py

This form was imported direct from my project, and contained the following definition:

from django import forms
from registration import forms as registrationforms
from django.utils.translation import ugettext_lazy as _

class RegistrationForm(registrationforms.RegistrationForm):
    """
    Form for user registration - adds checkbox to indicate you're a teacher
    """
    is_teacher = forms.BooleanField(required=False, widget=forms.CheckboxInput(), label=_(u'I teach drums/percussion'))

    def clean_email(self):
        """
        Query botscout to see if the email address is from a bot.
        """
        lEmail = self.cleaned_data['email']
        lConnection = httplib.HTTPConnection("botscout.com")
        lHeaders = {"Host" : "botscout.com",
            "User-Agent" : "Django",
            "Content-type": 'text/xml; charset="UTF-8"',
            "Content-length": "0",
            }
        lConnection.request("GET", "/test/?mail=%s" % lEmail, None, lHeaders)
        lResponseObject = lConnection.getresponse()
        lStatusCode = lResponseObject.status
        lResponse = lResponseObject.read()
        if lStatusCode == 200 and len(lResponse) > 0 and lResponse[0] == 'Y':
            raise forms.ValidationError("""Your email address appears on a bot register.  
                               If you are a real person, then please contact us via the feedback form and let us know.""")

        if len(lResponse) > 0 and lResponse[0] == '!':
            lErrorMessage = "Problems Accessing BotScout, %s:%s" % (lStatusCode, lResponse)
            send_mail('%s BotScout Error' % settings.EMAIL_SUBJECT_PREFIX,
                       lErrorMessage, 
                       'from@mail.com', 
                       ['to@mail.com'], 
                       fail_silently=True)

        return lEmail

Note that we've implemented clean_email to check the applicant against the botscout database.

views.py

The view was copied from django-registration and then modified slightly to save the checkbox value onto the user profile. I was able to simplify this function for my usage:

def register(request, backend, form_class=None):
    """
    Copied and modified from registration.views.register
    """
    backend = get_backend(backend)
    if request.method == 'POST':
        form = form_class(data=request.POST, files=request.FILES)
        if form.is_valid():
            new_user = backend.register(request, **form.cleaned_data)
            lProfile = new_user.get_profile()
            try:
                request.POST['is_teacher']
                lProfile.is_teacher = True
                lProfile.save()
            except KeyError:
                pass
            to, args, kwargs = backend.post_registration_redirect(request, new_user)
            return redirect(to, *args, **kwargs)
    else:
        form = form_class()

    context = RequestContext(request)

    return render_to_response('registration/registration_form.html',
                              { 'form': form },
                              context_instance=context)

I'm using the technique at http://drumcoder.co.uk/blog/2011/mar/26/auto-creating-django-profiles/ to ensure that the profile is always available.

References