Creating a custom user model in Django 1.6 - Part 1Published byGoogle Emmanuelle Delescolle on June 10, 2014, 11 a.m.
Welcome back to our Django tutorial series.
Before Django 1.5 customizing the user model was a bit of a hack as it involved creating a user profile with a one-to-one relationship to the user. All that changed in 1.5.
In this tutorial we are goin to see how to substitue Django's default user model with our own and allow the use of a user's e-mail instead of it's username during the login process.
Since 1.7 is not officially stable yet, this tutorial is meant for Django 1.6 but should also work with 1.7 (except for the South part which will be replaced in 1.7 by Django's own schema migration mechanism)
When forced to choose a login name on a website, you sometimes have to get creative because your usual login name has already been taken. This often leads to a lot of head scratching when, 3 years later, you have to remember that login name in order to get into that particular website.
To make things easier, the most commonly used method nowadays is to allow users to log in using either their username or their e-mail address.
By default Django requires a username in order to login, but it doesn't always have to be the case.
So let's get started!
First things first lets define our new user model. To do this, we'll first create an application dedicated to our new user and its authentication:
$ python manage.py startapp myauth
This user model is basically the same as the default django user model with a slightly different behaviour. But for the sake of it we will extend AbstractBaseUser instead of extending auth.User so that this tutorial can be used as a base for extending users in a broader way.
Edit myauth/models.py so that it looks like this:
from django.db import models import re import uuid from django.core import validators from django.utils import timezone from django.core.mail import send_mail from django.utils.http import urlquote from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager from django import forms class User(AbstractBaseUser, PermissionsMixin): username = models.CharField(_('username'), max_length=30, unique=True, help_text=_('Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters'), validators=[ validators.RegexValidator(re.compile('^[\w.@+-]+$'), _('Enter a valid username.'), _('invalid')) ]) first_name = models.CharField(_('first name'), max_length=30, blank=True, null=True) last_name = models.CharField(_('last name'), max_length=30, blank=True, null=True) email = models.EmailField(_('email address'), max_length=255) is_staff = models.BooleanField(_('staff status'), default=False, help_text=_('Designates whether the user can log into this admin site.')) is_active = models.BooleanField(_('active'), default=False, help_text=_('Designates whether this user should be treated as active. Unselect this instead of deleting accounts.')) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) receive_newsletter = models.BooleanField(_('receive newsletter'), default=False) USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email',] class Meta: verbose_name = _('user') verbose_name_plural = _('users') def get_full_name(self): full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): return self.first_name def email_user(self, subject, message, from_email=None): send_mail(subject, message, from_email, [self.email])
As you can see, this mimics Django's default user model, if you need to add fields to your model or specific validators, you can do it all here as with any other model.
Now User model is a bit specific, amongst other things it requires a Manager which has methods to create unpriviledged users as well as superusers (used from the command line manage.py createsuperuser) so let's create the manager by adding this class at the beginning of myauth/models.py:
class UserManager(BaseUserManager): def _create_user(self, username, email, password, is_staff, is_superuser, **extra_fields): now = timezone.now() if not username: raise ValueError(_('The given username must be set')) email = self.normalize_email(email) user = self.model(username=username, email=email, is_staff=is_staff, is_active=False, is_superuser=is_superuser, last_login=now, date_joined=now, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_user(self, username, email=None, password=None, **extra_fields): return self._create_user(username, email, password, False, False, **extra_fields) def create_superuser(self, username, email, password, **extra_fields): user=self._create_user(username, email, password, True, True, **extra_fields) user.is_active=True user.save(using=self._db) return user
As well as this line to the User class (in order to set the correct manager):
objects = UserManager()
Now let's add our application to settings.py and tell Django what model it should use as default User model by setting AUTH_USER_MODEL.
INSTALLED_APPS = ( . . . ## Add this line: 'myauth', ) ## Also add this at the bottom of the fille: AUTH_USER_MODEL = 'myauth.User'
And finally let's create the new tables in our database using south:
$ python manage.py schemamigration myauth --initial Creating migrations directory at '/home/emma/web-code/mybaseproject/myauth/migrations'... Creating __init__.py in '/home/emma/web-code/mybaseproject/myauth/migrations'... + Added model myauth.User + Added M2M table for groups on myauth.User + Added M2M table for user_permissions on myauth.User Created 0001_initial.py. You can now apply this migration with: ./manage.py migrate myauth $ python manage.py migrate myauth Running migrations for myauth: - Migrating forwards to 0001_initial. > myauth:0001_initial - Loading initial data for myauth. Installed 0 object(s) from 0 fixture(s)
It is always best to determine at the begining of a project whether you will need to use a custom user model or not, but it is not always possible as project requirements change during the life of most projects.
So if you already have existing users you'll need to also create a data migration but we'll see about that next week. We will also cover form creation for your new user model.
In the mean time, have a great week everyone and happy codingTutorial Django Custom user model