Professional Documents
Culture Documents
But that being said Django Official documentation suggests you have a
custom model even if you don’t want too so in future if you want to
add more information about the user you can do so which is more
likely if your app grows.
Application-specific data
The User model is meant to show information related to your user ’s
authentication or authentication point of view. You might even be
tempted to store other application-specific information related to
the user.
Since most users will have a profile picture, bio. Data like this
could be stored in another model which is referenced with an
OneToOneField with the User Model.
1.Proxy Model
2.Profile Model with OneToOneField with User Model
3.AbstractBaseUser to Create a Custom User Model
4.AbstractUser to Create a Custom User Model
1. Proxy Model
Proxy models are a feature that developers might come across and move
along without giving much importance. They can come in handy in many
situations.
A proxy model doesn’t get its own database table. Instead, it operates
on the original table.
When you don’t need to add extra data about but just want extra
methods or change the model’s query Manager.
class Person(User):
objects = PersonManager()
class Meta:
proxy = True
ordering = ('email', )
def do_something(self):
...
It’s the Foreign Key relation but with unique=True. So every row in a
table would have only one relating row in another table and vice
versa.
You should do this when you want to store profile related information
like a profile picture, bio, etc. Basically everything related to the
user that is not authentication specific.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.CharField(null=True, max_length=200)
birth_date = models.DateField(null=True, blank=True)
profile_pic = models.ImageField(default='default.jpg',
upload_to='profiles_pics')
hobby = models.CharField(null=True, max_length=200)
Now since the models are created, but they need to be created
whenever a user is created. We need to use signals to do the same.
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.CharField(null=True, max_length=200)
birth_date = models.DateField(null=True, blank=True)
profile_pic = models.ImageField(default='default.jpg',
upload_to='profiles_pics')
hobby = models.CharField(null=True, max_length=200)
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
Here, we are telling Django that whenever a save event occurs (signal
called post_save) create or save the profile depending on the
situation.
Since we have signals setup we don ’t have to save the Profile models.
If we save the User model the Profile models will also be saved.
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['profile_pic', 'bio']
It can be helpful in many cases like when you want to use email for
authentication instead of username. But there are better ways to do
the same by using AbstractUser instead of AbstractBaseUser .
This model would be compatible with all the built-in auth forms and
views, except for the user creation forms. This example illustrates
how most of the components work together, but is not intended to be
copied directly into projects for production use.
class MyUserManager(BaseUserManager):
def create_user(self, email, date_of_birth, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
date_of_birth=date_of_birth,
)
user.set_password(password)
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
date_of_birth = models.DateField()
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['date_of_birth']
def __str__(self):
return self.email
@property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
Then, to register this custom user model with Django ’s admin, the
following code would be required in the app ’s admin.py file:
from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
class UserCreationForm(forms.ModelForm):
"""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)
class Meta:
model = MyUser
fields = ('email', 'date_of_birth')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
class UserChangeForm(forms.ModelForm):
"""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 = MyUser
fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserChangeForm
add_form = UserCreationForm
Finally, specify the custom model as the default user model for your
project using the AUTH_USER_MODEL setting in your settings.py:
AUTH_USER_MODEL = 'users.MyUser'
class MyUser(AbstractUser):
bio = models.TextField(max_length=500, blank=True)
hobby = models.CharField(max_length=200, blank=True)
Django recommends having your own custom model even if you happy with
the out of the box User model.
What to do if I just need the default User Model and don ’t want to add
any other fields?
Do it like this:
from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
pass
def __str__(self):
return self.username
Referencing the User model
Now since you have changed your default User Model. You might need to
change the way you access it.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# Other Fields
class Profile(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
# Other Fields
or
from django.db import models
from django.conf import settings
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
# Other Fields
To store more information about Users like the profile picture, bio,
and other user-related information we created another Model called
Profile and we used OneToOneField to relate it to Custom User Model.
Conclusion
It’s always a good idea to use a custom user model if you are still
happy with the one provided by Django out of the box.
Let me know if this post helps you in any way in the comment section
below.