167đź‘Ť
The documentation explains this fully. AbstractUser
is a full User model, complete with fields, as an abstract class so that you can inherit from it and add your own profile fields and methods. AbstractBaseUser
only contains the authentication functionality, but no actual fields: you have to supply them when you subclass.
52đź‘Ť
The AbstractUser is basically just the “User” class you’re probably already used to. AbstractBaseUser makes fewer assumptions and you have to tell it what field represents the username, what fields are required, and how to manage those users.
If you’re just adding things to the existing user (i.e. profile data with extra fields), then use AbstractUser because it’s simpler and easier. If you want to rethink some of Django’s assumptions about authentication, then AbstractBaseUser gives you the power to do so.
- [Django]-How to monkey patch Django?
- [Django]-Django 1.5 custom User model error. "Manager isn't available; User has been swapped"
- [Django]-How to access Enum types in Django templates
30đź‘Ť
First of all, I explain AbstractUser then AbstractBaseUser. *You can see my answer explaining how to set up email
and password
authentication with AbstractUser
or AbstractBaseUser
and PermissionsMixin.
<AbstractUser>
AbstractUser
class initially has 11 fields same as default User class(model) as shown below and for the subclass of AbstractUser
class, you can add new fields, change and remove initial fields. *Keep it in mind that username
and email
fields in the initial fields of AbstractUser
class are special and only username
field has Unique Constraint.
These are the initial fields of AbstractUser
class which default User
class has as shown below:
id
password
last_login
is_superuser
username (Special, Unique Constraint)
first_name
last_name
email (Special)
is_staff
is_active
date_joined
Now, set pass
to CustomUser(AbstractUser)
class as shown below:
# "account/models.py"
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
pass
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Then, the initial fields of AbstractUser
class are created in SQLite as shown below:
Next, set age
and gender
fields for CustomUser(AbstractUser)
class as shown below:
# "account/models.py"
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
age = models.IntegerField()
gender = models.CharField(max_length=100)
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Then, age
and gender
fields are created with the initial fields of AbstractUser
class as shown below:
Next, change all the initial fields of AbstractUser
class by setting models.CharField(max_length=100)
to them but id
field needs primary_key=True
to have Primary Key otherwise there is an error and username
field needs unique=True
to have Unique Constraint otherwise there is a warning:
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser): # ↓ Here ↓
id = models.CharField(max_length=100, primary_key=True)
password = models.CharField(max_length=100)
last_login = models.CharField(max_length=100)
is_superuser = models.CharField(max_length=100) # ↓ Here
username = models.CharField(max_length=100, unique=True)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
email = models.CharField(max_length=100)
is_staff = models.CharField(max_length=100)
is_active = models.CharField(max_length=100)
date_joined = models.CharField(max_length=100)
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Then, all the initial fields of AbstractUser
class are changed as shown below:
Next, remove password
, last_login
, is_superuser
and username
fields by setting None
to them as shown below. *Keep it in mind that id
field can never ever be removed even if setting None
to it and USERNAME_FIELD
must have one existing field and by default, username
field which has Unique Constraint is set to USERNAME_FIELD
so if removing username
field by setting None
to it, you also need to remove username
field from USERNAME_FIELD
by setting one existing field as shown below otherwise there is an error so in this example below, there are 7 existing fields id
, first_name
, last_name
, email
, is_staff
, is_active
and date_joined
so change USERNAME_FIELD
from username
field to last_name
field by settiing last_name
field with unique=True
to USERNAME_FIELD
as shown below. *Keep it in mind that like last_name
field, the existing field set to USERNAME_FIELD
needs unique=True
to have Unique Constraint as shown below otherwise there is a warning but when setting id
field which has Primary Key to USERNAME_FIELD
, it doesn’t need unique=True
to have Unique Constraint:
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
password = None
last_login = None
is_superuser = None
username = None # Here
last_name = models.CharField(max_length=150, unique=True)
USERNAME_FIELD = 'last_name' # Here
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Then, as shown below, password
, last_login
, is_superuser
and username
fields are removed and last_name
field has Unique Constraint:
Next again, remove password
, last_login
, is_superuser
and username
fields by setting None
to them as shown below but this time, change USERNAME_FIELD
from username
field to email
field by settiing email
field with unique=True
to USERNAME_FIELD
as shown below. *Keep it in mind that by default, email
field is also set to REQUIRED_FIELDS
and it’s not allowed to set the same field to both USERNAME_FIELD
and REQUIRED_FIELDS
at the same time otherwise there is an error so set no fields to REQUIRED_FIELDS
as shown below. *Keep it in mind that it’s ok that no fields are set to REQUIRED_FIELDS
as shown below:
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
password = None
last_login = None
is_superuser = None
username = None # Here
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email' # Here
REQUIRED_FIELDS = [] # Here
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Then, as shown below, password
, last_login
, is_superuser
and username
fields are removed and email
field has Unique Constraint:
This code below is the part of AbstractUser
class in Django on Github. You can see the defined fields, USERNAME_FIELD = "username"
, REQUIRED_FIELDS = ["email"]
and AbstractUser
class is actually the subclass of AbstractBaseUser
class which I’m going to explain next:
# "django/contrib/auth/models.py"
class AbstractUser(AbstractBaseUser, PermissionsMixin):
username_validator = UnicodeUsernameValidator()
username = models.CharField(
_("username"),
max_length=150,
unique=True,
help_text=_(
"Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."
),
validators=[username_validator],
error_messages={
"unique": _("A user with that username already exists."),
},
)
first_name = models.CharField(_("first name"), max_length=150, blank=True)
last_name = models.CharField(_("last name"), max_length=150, blank=True)
email = models.EmailField(_("email address"), blank=True)
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=True,
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)
objects = UserManager()
EMAIL_FIELD = "email"
USERNAME_FIELD = "username"
REQUIRED_FIELDS = ["email"]
<AbstractBaseUser>
AbstractBaseUser
class initially has 3 fields as shown below and for the subclass of AbstractBaseUser
class, you can add new fields and change and remove initial fields same as AbstractUser
class.
These are the initial fields of AbstractBaseUser
class as shown below:
id
password
last_login
Now, set password
field with unique=True
to USERNAME_FIELD
in CustomUser(AbstractBaseUser)
class as shown below. *Keep it in mind that AbstractBaseUser
class also has USERNAME_FIELD
and by default, no field is set to USERNAME_FIELD
so you need to set one existing field to it as shown below otherwise there is an error. In addition, no fields are set to REQUIRED_FIELDS
:
# "account/models.py"
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
class CustomUser(AbstractBaseUser):        # ↓ Here ↓ 
password = models.CharField(max_length=128, unique=True)
# ↓ Here ↓
USERNAME_FIELD = 'password'
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Then, the initial fields of AbstractBaseUser
class are created in SQLite as shown below:
Next, set age
and gender
fields for CustomUser(AbstractBaseUser)
class and set age
field with unique=True
to USERNAME_FIELD
as shown below:
# "account/models.py"
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
class CustomUser(AbstractBaseUser):
age = models.IntegerField(unique=True)
gender = models.CharField(max_length=100)
USERNAME_FIELD = 'age'
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Then, age
and gender
fields are created with the initial fields of AbstractBaseUser
class and Unique Constraint is set to age
field as shown below:
Next, change all the initial fields of AbstractBaseUser
class by setting models.CharField(max_length=100)
to them and set password
field with unique=True
to USERNAME_FIELD
and same as AbstractUser
class, id
field needs primary_key=True
to have Primary Key otherwise there is an error:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
class CustomUser(AbstractBaseUser): # ↓ Here ↓
id = models.CharField(max_length=100, primary_key=True)
password = models.CharField(max_length=100, unique=True)
last_login = models.CharField(max_length=100)
USERNAME_FIELD = 'password'
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Then, all the initial fields of AbstractBaseUser
class are changed and Unique Constraint is set to password
field as shown below:
Next, remove password
and last_login
fields by setting None
to them and set only one existing field id
to USERNAME_FIELD
as shown below. *Keep it in mind that same as AbstractUser
, id
field can never ever be removed even if setting None
to it and when setting id
field which has Primary Key to USERNAME_FIELD
, it doesn’t need unique=True
to have Unique Constraint:
from django.contrib.auth.models import AbstractBaseUser
class CustomUser(AbstractBaseUser):
password = None
last_login = None
USERNAME_FIELD = 'id'
Then, run this command below:
python manage.py makemigrations && python manage.py migrate
Then, as shown below, password
and last_login
fields are removed:
This code below is the part of AbstractBaseUser
class in Django on Github. You can see the defined fields, USERNAME_FIELD
is not defined and REQUIRED_FIELDS = []
:
# "django/contrib/auth/base_user.py"
class AbstractBaseUser(models.Model):
password = models.CharField(_("password"), max_length=128)
last_login = models.DateTimeField(_("last login"), blank=True, null=True)
is_active = True
REQUIRED_FIELDS = []
- [Django]-Django-allauth: Linking multiple social accounts to a single user
- [Django]-How can I use redis with Django?
- [Django]-Convert Django Model object to dict with all of the fields intact
4đź‘Ť
AbstractUser class is the subclass of AbstractBaseUser and PermissionsMixin classes and AbstractUser
class has 11 fields same as default User class(model) as shown below:
id
password
last_login
is_superuser
username
first_name
last_name
email
is_staff
is_active
date_joined
AbstractBaseUser
class is the superclass of AbstractUser
class and AbstractBaseUser
class has 3 fields as shown below:
id
password
last_login
In addition, PermissionsMixin
class is the superclass of AbstractUser
and PermissionsMixin
class has 2 fields as shown below:
id
is_superuser
*You can see my answer explaining how to set up email and password authentication with AbstractUser
or AbstractBaseUser
and PermissionsMixin
.
- [Django]-ManyRelatedManager object is not iterable
- [Django]-Django import error – no module named django.conf.urls.defaults
- [Django]-Django import error – No module named core.management
0đź‘Ť
Main difference basically lies on Usecase. Say for example you no longer need the existing User class provided by Django and you only care about authentication functionalities provided by the User class and your own custom fields. In that case, you should use AbstractBaseUser. In another case, you want to use existing User Fields and functionalities but on top of that you would like to ad some extra fields and methods. In that case, you should use AbstractUser.
- [Django]-How to read the database table name of a Model instance?
- [Django]-Django logging of custom management commands
- [Django]-Whats the difference between a OneToOne, ManyToMany, and a ForeignKey Field in Django?