AbstractUser
和AbstractBaseUser
看起来非常相似。from django.contrib.auth.models import AbstractUser, AbstractBaseUser
两者之间有什么区别?
AbstractUser
和AbstractBaseUser
看起来非常相似。from django.contrib.auth.models import AbstractUser, AbstractBaseUser
文档对此作了详细解释。 AbstractUser
是完整的用户模型,包含字段,作为抽象类供您继承并添加自己的配置文件字段和方法。而 AbstractBaseUser
仅包含认证功能,但没有实际字段:当你创建子类时,必须提供它们。
AbstractUser基本上就是你可能已经习惯了的"用户(User)"类。AbstractBaseUser做出的假设更少,您需要告诉它哪个字段代表用户名,哪些字段是必需的,以及如何管理这些用户。
如果您只是在现有用户中添加一些内容(例如具有额外字段的配置文件数据),则使用AbstractUser因为它更简单易用。如果您想重新考虑Django关于认证的某些假设,那么AbstractBaseUser能够赋予您这样做的能力。
email
和password
验证来设置AbstractUser
或AbstractBaseUser
以及PermissionsMixin。
AbstractUser
类最初有11个字段,与默认的User类(模型)相同,如下所示。对于AbstractUser
类的子类,您可以添加新字段,更改和删除初始字段。请记住,AbstractUser
类中的username
和email
字段是特殊的,只有username
字段具有唯一约束。
这些是AbstractUser
类的初始字段,与默认的User
类相同,如下所示:
id
password
last_login
is_superuser
username (Special, Unique Constraint)
first_name
last_name
email (Special)
is_staff
is_active
date_joined
现在,按照下面的示例,将pass
设置为CustomUser(AbstractUser)
类:
# "account/models.py"
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
pass
python manage.py makemigrations && python manage.py migrate
AbstractUser
类的初始字段在SQLite中创建如下所示:
接下来,按照下面的示例,为CustomUser(AbstractUser)
类设置age
和gender
字段:# "account/models.py"
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
age = models.IntegerField()
gender = models.CharField(max_length=100)
python manage.py makemigrations && python manage.py migrate
AbstractUser
类的初始字段的age
和gender
字段:
接下来,通过将AbstractUser
类的所有初始字段设置为models.CharField(max_length=100)
,来进行更改,但是id
字段需要primary_key=True
来拥有主键,否则会出现错误,而username
字段需要unique=True
来拥有唯一约束,否则会出现警告: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)
python manage.py makemigrations && python manage.py migrate
AbstractUser
类的所有初始字段如下所示进行了更改:
接下来,通过将以下字段设置为None
来移除password
、last_login
、is_superuser
和username
字段。*请记住,即使将id
字段设置为None
,也不能删除它,并且USERNAME_FIELD
必须有一个现有的字段,默认情况下,username
字段被设置为USERNAME_FIELD
,该字段具有唯一约束条件,因此如果通过将其设置为None
来删除username
字段,则还需要通过将一个现有字段设置为USERNAME_FIELD
来从USERNAME_FIELD
中删除username
字段,如下所示,否则会出错,因此在下面的示例中,存在7个现有字段id
、first_name
、last_name
、email
、is_staff
、is_active
和date_joined
,因此将USERNAME_FIELD
从username
字段更改为last_name
字段,通过将last_name
字段设置为unique=True
,将last_name
字段设置为USERNAME_FIELD
,如下所示。*请记住,像last_name
字段一样,设置为USERNAME_FIELD
的现有字段需要unique=True
以具有唯一约束条件,如下所示,否则会出现警告,但是当将具有主键的id
字段设置为USERNAME_FIELD
时,它不需要unique=True
以具有唯一约束条件。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
python manage.py makemigrations && python manage.py migrate
password
、last_login
、is_superuser
和username
字段被删除,而last_name
字段具有唯一约束:
下一步,再次移除password
、last_login
、is_superuser
和username
字段,将它们设置为None
,如下所示。但是这次,将USERNAME_FIELD
从username
字段更改为email
字段,通过将email
字段设置为unique=True
,将其设置为USERNAME_FIELD
,如下所示。请记住,默认情况下,email
字段也被设置为REQUIRED_FIELDS
,不允许同时将同一个字段设置为USERNAME_FIELD
和REQUIRED_FIELDS
,否则会出错,因此请将REQUIRED_FIELDS
设置为no fields,如下所示。请记住,将REQUIRED_FIELDS
设置为no fields也是可以的,如下所示: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
python manage.py makemigrations && python manage.py migrate
password
、last_login
、is_superuser
和username
字段被移除,而email
字段则具有唯一约束。
下面的代码是 Django 在 Github 上的 AbstractUser
类的部分。您可以看到定义的字段,USERNAME_FIELD = "username"
,REQUIRED_FIELDS = ["email"]
,并且 AbstractUser
类实际上是 AbstractBaseUser
类的子类,我接下来会解释:
# "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
类最初有以下3个字段,对于AbstractBaseUser
类的子类,您可以添加新字段,并像AbstractUser
类一样更改和删除初始字段。
以下是AbstractBaseUser
类的初始字段:
id
password
last_login
CustomUser(AbstractBaseUser)
类中,将password
字段设置为unique=True
的USERNAME_FIELD
,如下所示。请记住,AbstractBaseUser
类也有USERNAME_FIELD
,默认情况下没有字段设置为USERNAME_FIELD
,因此您需要按照下面所示设置一个现有字段,否则会出错。此外,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'
python manage.py makemigrations && python manage.py migrate
AbstractBaseUser
类的初始字段在SQLite中创建如下所示:
接下来,为CustomUser(AbstractBaseUser)
类设置age
和gender
字段,并将age
字段设置为unique=True
,如下所示:将age
字段设置为USERNAME_FIELD
。# "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'
python manage.py makemigrations && python manage.py migrate
AbstractBaseUser
类的初始字段创建age
和gender
字段,并将age
字段设置为唯一约束,如下所示:
接下来,通过将AbstractBaseUser
类的所有初始字段设置为models.CharField(max_length=100)
,并将password
字段设置为unique=True
,将USERNAME_FIELD
设置为与AbstractUser
类相同。此外,id
字段需要设置primary_key=True
以拥有主键,否则会出现错误。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'
python manage.py makemigrations && python manage.py migrate
AbstractBaseUser
类的所有初始字段都被更改,并且password
字段被设置为唯一约束,如下所示:
接下来,通过将password
和last_login
字段设置为None
来移除它们,并且只将一个现有字段id
设置为USERNAME_FIELD
,如下所示。请记住,与AbstractUser
一样,id
字段永远不能被移除,即使将其设置为None
,并且当将具有主键的id
字段设置为USERNAME_FIELD
时,不需要unique=True
来拥有唯一约束:from django.contrib.auth.models import AbstractBaseUser
class CustomUser(AbstractBaseUser):
password = None
last_login = None
USERNAME_FIELD = 'id'
python manage.py makemigrations && python manage.py migrate
password
和last_login
字段被移除:
以下代码是Django在Github上的AbstractBaseUser
类的一部分。你可以看到定义的字段,USERNAME_FIELD
没有被定义,而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 = []
AbstractUser类是AbstractBaseUser和PermissionsMixin类的子类,AbstractUser
类与默认的User类(模型)具有相同的11个字段,如下所示:
id
password
last_login
is_superuser
username
first_name
last_name
email
is_staff
is_active
date_joined
AbstractBaseUser
类是AbstractUser
类的超类,而AbstractBaseUser
类有以下3个字段:id
password
last_login
PermissionsMixin
类是 AbstractUser
的超类,并且 PermissionsMixin
类具有如下所示的2个字段:id
is_superuser
您可以查看我的答案,其中解释了如何使用AbstractUser
或AbstractBaseUser
和PermissionsMixin
设置电子邮件和密码验证。
主要区别基本上在于用例。例如,假设您不再需要Django提供的现有User类,并且您只关心User类提供的身份验证功能和自己的自定义字段。在这种情况下,您应该使用AbstractBaseUser。在另一种情况下,您想要使用现有的User字段和功能,但是在此基础上还想添加一些额外的字段和方法。在这种情况下,您应该使用AbstractUser。