Tuesday, January 31, 2012

Customising django registration - no activation email or just a username

A client had a need for removing the email activation from the standard django registration process and a prototype system I am working on needed the ability to create a user from just a username, so I was delighted to find that the current django-registration development version makes this kind of customisation easy.

Here's how:

In the registration folder, there is a new folder called backends. Create a new folder, for example myreg, and put two files in it.

The __init__.py does the main work:

In this example there are two changes from the default, there is no email activation required and the registration form also asks for the users first and last names.

__init__.py


from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.auth import login
from django.contrib.auth.models import User
from django import forms

from registration import signals
from registration.forms import RegistrationForm


class MyRegBackend(object):
"""
A registration backend which implements the simplest possible
workflow: a user supplies a username, email address and password
(the bare minimum for a useful account), and is immediately signed
up and logged in.

"""
def register(self, request, **kwargs):
"""
Create and immediately log in a new user.

"""
username, email, password, first_name, last_name = kwargs['username'], kwargs['email'], kwargs['password1'], kwargs['first_name'], kwargs['last_name']

u = User.objects.create_user(username, email, password)
u.first_name = first_name
u.last_name = last_name
u.save()

new_user = authenticate(username=username, password=password)

login(request, new_user)
signals.user_registered.send(sender=self.__class__,
user=new_user,
request=request)
return new_user

def activate(self, **kwargs):
raise NotImplementedError

def registration_allowed(self, request):
"""
Indicate whether account registration is currently permitted,
based on the value of the setting ``REGISTRATION_OPEN``. This
is determined as follows:

* If ``REGISTRATION_OPEN`` is not specified in settings, or is
set to ``True``, registration is permitted.

* If ``REGISTRATION_OPEN`` is both specified and set to
``False``, registration is not permitted.

"""
return getattr(settings, 'REGISTRATION_OPEN', True)

def get_form_class(self, request):

class MyRegForm(RegistrationForm):

"""
add first and last names to the form
"""
first_name = forms.CharField(
label='First name',
max_length=30,
required=True)
last_name = forms.CharField(
label='Last name',
max_length=30,
required=True)


return MyRegForm

def post_registration_redirect(self, request, user):
"""
After registration, redirect to the home page

"""

return ("/", (), {})

def post_activation_redirect(self, request, user):
raise NotImplementedError


The second file is urls.py where you need to point to your new backend

urls.py


from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template

from registration.views import activate
from registration.views import register


urlpatterns = patterns('',
url(r'^register/$',
register,
{'backend': 'registration.backends.myreg.MyRegBackend'},
name='registration_register'),
url(r'^register/closed/$',
direct_to_template,
{'template': 'registration/registration_closed.html'},
name='registration_disallowed'),
(r'', include('registration.auth_urls')),
)



Now an even simpler version. Just enter a username and the user is created and you are logged in. Note that I wanted a default password so I made password1 a hidden field on the form with the value I wanted so that is how it is able to create the user. I could also have hard coded it into the register method below.


__init__.py


from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.auth import login
from django.contrib.auth.models import User

from registration import signals
from registration.forms import RegistrationForm


class MyReg2Backend(object):
"""
A registration backend which implements the simplest possible
workflow: a user supplies a username, email address and password
(the bare minimum for a useful account), and is immediately signed
up and logged in.

"""
def register(self, request, **kwargs):
"""
Create and immediately log in a new user.

"""
username, email, password = kwargs['username'], kwargs['email'], kwargs['password1']
User.objects.create_user(username, email, password)

# authenticate() always has to be called before login(), and
# will return the user we just created.
new_user = authenticate(username=username, password=password)
login(request, new_user)
signals.user_registered.send(sender=self.__class__,
user=new_user,
request=request)
return new_user

def activate(self, **kwargs):
raise NotImplementedError

def registration_allowed(self, request):
"""
Indicate whether account registration is currently permitted,
based on the value of the setting ``REGISTRATION_OPEN``. This
is determined as follows:

* If ``REGISTRATION_OPEN`` is not specified in settings, or is
set to ``True``, registration is permitted.

* If ``REGISTRATION_OPEN`` is both specified and set to
``False``, registration is not permitted.

"""
return getattr(settings, 'REGISTRATION_OPEN', True)

def get_form_class(self, request):
return RegistrationForm

def post_registration_redirect(self, request, user):
"""
After registration, redirect to the user's account page.

"""
return (user.get_absolute_url(), (), {})

def post_activation_redirect(self, request, user):
raise NotImplementedError



Now in urls.py you just need to call your new backend

urls.py


from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template

from registration.views import activate
from registration.views import register


urlpatterns = patterns('',
url(r'^register/$',
register,
{'backend': 'registration.backends.myreg2.MyReg2Backend', 'template_name': 'registration/registration_form_quick.html'},
name='registration_register'),
url(r'^register/closed/$',
direct_to_template,
{'template': 'registration/registration_closed.html'},
name='registration_disallowed'),
(r'', include('registration.auth_urls')),
)