4. Basic
From Django 1.5 onwards, the official preferred way to attach ForeignKey, OneToOneField,
or ManyToManyField to User is as follows:
from django.conf import settings
from django.db import models
!
class IceCreamStore(models.model):
owner = models.OneToOneField(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=255)
6. Warranty
We suggest that you carefully try out option #1
below, as it should work with a minimum of effort.
For Django 1.5-style custom User model definitions,
we recommend option #2 and option #3 for new
projects only.
!
This is is because custom User model definitions for
option #2 and option #3 adds new User tables to
the database that will not have the existing project
data. Unless project-specific steps are taken to
address matters, migration means ORM connections
to related objects will be lost.
7. Option 1 - Link back
You continue to use User (called preferably via
django.contrib.auth.get user model()) and keep your related
fields in a separate model (e.g. Profile).
from django.conf import settings
from django.db import models
class UserProfile(models.Model):
# If you do this you need to either have a post_save signal or
#
redirect to a profile_edit view on initial login.
user = models.OneToOneField(settings.AUTH_USER_MODEL)
favorite_ice_cream = models.CharField(max_length=30)
8. Option 2 AbstractUser
Choose this option if you like Django’s User model fields the
way they are, but need extra fields
!from
django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import ugettext_lazy as _
!
class KarmaUser(AbstractUser):
karma = models.PositiveIntegerField(_("karma"),
default=0,
blank=True)
#Setting.py
AUTH_USER_MODEL = "profile.KarmaUser"
9. Option 3 - Subclass
AbstractBaseUser
AbstractBaseUser is the bare-bones option with only 3 fields:
password, last login, and is active.
!
Let’s try it out with a custom User model for the Two
Scoops project. Here are our requirements:
We need an email address.
We need to handle permissions per the traditional
django.contrib.auth.models use of PermissionsMixin;
providing standard behavior for the Django admin.
We don’t need the first or last name of a user.
We need to know their favorite ice cream topping.
•
•
•
•
10. Option 3 - cont.(1)
1. Start from model.
2. Model.UserManager create User -> override it to create
TwoScoopsUser
3. We need TwoScoopsUser!
class TwoScoopsUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
db_index=True,
)
favorite_topping = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
!
!
objects = TwoScoopsUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['favorite_topping']
12. Option 3 - cont. (3)
Let’s write Model.UserManager to create TwoScoopsUser
class TwoScoopsUserManager(BaseUserManager):
def create_user(self, email, favorite_topping, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
##Skip…
user = self.model(
email=TwoScoopsUserManager.normalize_email(email),
favorite_topping=favorite_topping,
)
!
user.set_password(password)
user.save(using=self._db)
return user
13. Option 3 - cont. (4)
Let’s write Model.UserManager to create TwoScoopsUser
!
def create_superuser(self, email, favorite_topping, password):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user = self.create_user(email,
password=password,
favorite_topping=favorite_topping
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
14. Option 3 - Let Admin
show your data.
Basically, override contrib.auth.admin …
class TwoScoopsUserAdmin(UserAdmin):
# The forms to add and change user instances
form = TwoScoopsUserChangeForm
add_form = TwoScoopsUserCreationForm
!
!
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ("email", "is_staff", "favorite_topping")
list_filter = ("is_staff", "is_superuser", "is_active", "groups")
search_fields = ("email", "favorite_topping")
ordering = ("email",)
filter_horizontal = ("groups", "user_permissions",)
fieldsets = (
(None, {"fields": ("email", "password")}),
("Personal info", {"fields": ("favorite_topping",)}),
("Permissions", {"fields": ("is_active", "is_staff", "is_superuser", "groups", "user_permissions")}),
("Important dates", {"fields": ("last_login",)}),
)
add_fieldsets = ((None, {
"classes": ("wide",),
"fields": ("email", "favorite_topping", "password1", "password2")}), )
15. Option 3 - Let Admin
show your data. (2)
Implement your forms
class TwoScoopsUserCreationForm(UserCreationForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
#favorite_topping = forms.CharField( label='Faborate topping', widget=forms.TextInput)
!
class Meta:
model = TwoScoopsUser
fields = ('email', 'favorite_topping')
class TwoScoopsUserChangeForm(UserChangeForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
!
class Meta:
model = TwoScoopsUser
fields = ["email", "password", "favorite_topping", "is_active",
"is_staff", "is_superuser", "groups", "user_permissions",
"last_login"]