Django中AbstractUser和AbstractBaseUser的区别?

Pra*_*tal 41 django

使用AbstractUserAbstractBaseUser看起来非常相似.

from django.contrib.auth.models import AbstractUser, AbstractBaseUser
Run Code Online (Sandbox Code Playgroud)

两者有什么区别?

Dan*_*man 66

文件充分说明了这一点.AbstractUser是一个完整的用户模型,包含字段,作为抽象类,以便您可以继承它并添加自己的配置文件字段和方法.AbstractBaseUser仅包含身份验证功能,但不包含实际字段:您必须在子类时提供它们.


小智 30

首先,我解释AbstractUser然后AbstractBaseUser。*您可以看到我的答案,解释如何使用或和PermissionsMixin设置emailpassword身份验证。AbstractUserAbstractBaseUser

\n

<抽象用户>

\n

AbstractUser类最初有 11 个字段,与默认用户类(模型)相同,如下所示,对于AbstractUser类的子类,您可以添加新字段、更改和删除初始字段。*请记住,类的初始字段中的username和字段是特殊的,并且只有字段具有Unique ConstraintemailAbstractUserusername

\n

AbstractUser这些是默认类具有的类的初始字段,User如下所示:

\n
id\npassword\nlast_login\nis_superuser\nusername (Special, Unique Constraint)\nfirst_name\nlast_name\nemail (Special)\nis_staff\nis_active\ndate_joined\n
Run Code Online (Sandbox Code Playgroud)\n

现在,设置passCustomUser(AbstractUser)类,如下所示:

\n
# "account/models.py"\n\nfrom django.contrib.auth.models import AbstractUser\n\nclass CustomUser(AbstractUser):\n    pass\n
Run Code Online (Sandbox Code Playgroud)\n

然后,运行以下命令:

\n
python manage.py makemigrations && python manage.py migrate\n
Run Code Online (Sandbox Code Playgroud)\n

然后,在SQLiteAbstractUser中创建类的初始字段,如下所示:

\n

在此输入图像描述

\n

接下来,设置类agegender字段CustomUser(AbstractUser),如下所示:

\n
# "account/models.py"\n\nfrom django.contrib.auth.models import AbstractUser\n\nclass CustomUser(AbstractUser):\n    age = models.IntegerField()\n    gender = models.CharField(max_length=100)\n
Run Code Online (Sandbox Code Playgroud)\n

然后,运行以下命令:

\n
python manage.py makemigrations && python manage.py migrate\n
Run Code Online (Sandbox Code Playgroud)\n

然后,使用初始字段创建age字段genderAbstractUser如下所示:

\n

在此输入图像描述

\n

AbstractUser接下来,通过设置来更改类的所有初始字段models.CharField(max_length=100),但id字段需要primary_key=True主键,否则会出现错误,username字段需要unique=True唯一约束,否则会出现警告:

\n
from django.db import models\nfrom django.contrib.auth.models import AbstractUser\n\nclass CustomUser(AbstractUser):           # \xe2\x86\x93 Here \xe2\x86\x93\n    id = models.CharField(max_length=100, primary_key=True)\n    password = models.CharField(max_length=100)\n    last_login = models.CharField(max_length=100)\n    is_superuser = models.CharField(max_length=100) # \xe2\x86\x93 Here\n    username = models.CharField(max_length=100, unique=True)\n    first_name = models.CharField(max_length=100)\n    last_name = models.CharField(max_length=100)\n    email = models.CharField(max_length=100)\n    is_staff = models.CharField(max_length=100)\n    is_active = models.CharField(max_length=100)\n    date_joined = models.CharField(max_length=100)\n
Run Code Online (Sandbox Code Playgroud)\n

然后,运行以下命令:

\n
python manage.py makemigrations && python manage.py migrate\n
Run Code Online (Sandbox Code Playgroud)\n

然后,类的所有初始字段AbstractUser都更改如下:

\n

在此输入图像描述

\n

接下来,通过设置来删除passwordlast_login和字段is_superuser,如下所示。*请记住,即使设置为该字段,也永远无法删除它,并且必须有一个现有字段,并且默认情况下,具有唯一约束的字段设置为,因此如果通过设置来删除字段,您还需要删除字段from通过设置一个现有字段,如下所示,否则会出现错误,因此在下面的示例中,有 7 个现有字段, , , , , ,因此通过设置字段to来更改字段,如下所示。*请记住,与字段一样,设置为 的现有字段需要具有唯一约束,如下所示,否则会出现警告,但当将主键设置为 的字段时,不需要具有唯一约束usernameNoneidNoneUSERNAME_FIELDusernameUSERNAME_FIELDusernameNoneusernameUSERNAME_FIELDidfirst_namelast_nameemailis_staffis_activedate_joinedUSERNAME_FIELDusernamelast_namelast_nameunique=TrueUSERNAME_FIELDlast_nameUSERNAME_FIELDunique=TrueidUSERNAME_FIELDunique=True

\n
from django.db import models\nfrom django.contrib.auth.models import AbstractUser\n\nclass CustomUser(AbstractUser):\n    password = None\n    last_login = None\n    is_superuser = None\n    username = None                              # Here\n    last_name = models.CharField(max_length=150, unique=True)\n    \n    USERNAME_FIELD = \'last_name\' # Here\n
Run Code Online (Sandbox Code Playgroud)\n

然后,运行以下命令:

\n
python manage.py makemigrations && python manage.py migrate\n
Run Code Online (Sandbox Code Playgroud)\n

然后,如下所示,删除passwordlast_loginis_superuser和字段,并且字段具有Unique Constraintusernamelast_name

\n

在此输入图像描述

\n

接下来,再次通过设置删除passwordlast_login和字段,如下所示,但这一次,通过设置字段to来更改字段is_superuser,如下所示。*请记住,默认情况下,字段也设置为,并且不允许同时为两者设置相同的字段,否则会出现错误,因此不要设置任何字段,如下所示。*请记住,没有字段设置为如下所示是可以的:usernameNoneUSERNAME_FIELDusernameemailemailunique=TrueUSERNAME_FIELDemailREQUIRED_FIELDSUSERNAME_FIELDREQUIRED_FIELDSREQUIRED_FIELDSREQUIRED_FIELDS

\n
from django.db import models\nfrom django.contrib.auth.models import AbstractUser\n\nclass CustomUser(AbstractUser):\n    password = None\n    last_login = None\n    is_superuser = None\n    username = None           # Here               \n    email = models.EmailField(unique=True)\n\n    USERNAME_FIELD = \'email\' # Here\n    REQUIRED_FIELDS = [] # Here\n
Run Code Online (Sandbox Code Playgroud)\n

然后,运行以下命令:

\n
python manage.py makemigrations && python manage.py migrate\n
Run Code Online (Sandbox Code Playgroud)\n

然后,如下所示,删除passwordlast_loginis_superuser和字段,并且字段具有Unique Constraintusernameemail

\n

在此输入图像描述

\n

下面的代码是Github 上 Django 中的类的一部分AbstractUser。您可以看到定义的字段USERNAME_FIELD = "username"REQUIRED_FIELDS = ["email"]classAbstractUser实际上是 class 的子类AbstractBaseUser,我接下来将对此进行解释:

\n
# "django/contrib/auth/models.py"\n\nclass AbstractUser(AbstractBaseUser, PermissionsMixin):\n\n    username_validator = UnicodeUsernameValidator()\n\n    username = models.CharField(\n        _("username"),\n        max_length=150,\n        unique=True,\n        help_text=_(\n            "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."\n        ),\n        validators=[username_validator],\n        error_messages={\n            "unique": _("A user with that username already exists."),\n        },\n    )\n    first_name = models.CharField(_("first name"), max_length=150, blank=True)\n    last_name = models.CharField(_("last name"), max_length=150, blank=True)\n    email = models.EmailField(_("email address"), blank=True)\n    is_staff = models.BooleanField(\n        _("staff status"),\n        default=False,\n        help_text=_("Designates whether the user can log into this admin site."),\n    )\n    is_active = models.BooleanField(\n        _("active"),\n        default=True,\n        help_text=_(\n            "Designates whether this user should be treated as active. "\n            "Unselect this instead of deleting accounts."\n        ),\n    )\n    date_joined = models.DateTimeField(_("date joined"), default=timezone.now)\n\n    objects = UserManager()\n\n    EMAIL_FIELD = "email"\n    USERNAME_FIELD = "username"\n    REQUIRED_FIELDS = ["email"]\n
Run Code Online (Sandbox Code Playgroud)\n

<抽象基础用户>

\n

AbstractBaseUser类最初有 3 个字段,如下所示,对于AbstractBaseUser类的子类,您可以添加新字段以及与类相同的更改和删除初始字段AbstractUser

\n

这些是类的初始字段AbstractBaseUser,如下所示:

\n
id\npassword\nlast_login\n
Run Code Online (Sandbox Code Playgroud)\n

现在,在类password中将字段设置为unique=Trueto ,如下所示。*请记住,类也有,并且默认情况下没有设置任何字段,因此您需要为其设置一个现有字段,如下所示,否则会出现错误。此外,没有字段设置为:USERNAME_FIELDCustomUser(AbstractBaseUser)AbstractBaseUserUSERNAME_FIELDUSERNAME_FIELDREQUIRED_FIELDS

\n
# "account/models.py"\n\nfrom django.db import models\nfrom django.contrib.auth.models import AbstractBaseUser\n\nclass CustomUser(AbstractBaseUser):\xe3\x80\x80\xe3\x80\x80\xe3\x80\x80\xe3\x80\x80\xe3\x80\x80\xe3\x80\x80\xe3\x80\x80 # \xe2\x86\x93 Here \xe2\x86\x93\xe3\x80\x80\n    password = models.CharField(max_length=128, unique=True)\n    # \xe2\x86\x93 Here \xe2\x86\x93\n    USERNAME_FIELD = \'password\'\n
Run Code Online (Sandbox Code Playgroud)\n

然后,运行以下命令:

\n
python manage.py makemigrations && python manage.py migrate\n
Run Code Online (Sandbox Code Playgroud)\n

然后,在SQLiteAbstractBaseUser中创建类的初始字段,如下所示:

\n

在此输入图像描述

\n

接下来,设置类agegender字段,并使用toCustomUser(AbstractBaseUser)设置age字段,如下所示:unique=TrueUSERNAME_FIELD

\n
# "account/models.py"\n\nfrom django.db import models\nfrom django.contrib.auth.models import AbstractBaseUser\n\nclass CustomUser(AbstractBaseUser):\n    age = models.IntegerField(unique=True)\n    gender = models.CharField(max_length=100)\n\n    USERNAME_FIELD = \'age\'\n
Run Code Online (Sandbox Code Playgroud)\n

然后,运行以下命令:

\n
python manage.py makemigrations && python manage.py migrate\n
Run Code Online (Sandbox Code Playgroud)\n

然后,使用类的初始字段创建字段age,并将唯一约束设置为字段,如下所示:genderAbstractBaseUserage

\n

在此输入图像描述

\n

AbstractBaseUser接下来,通过设置来更改类的所有初始字段models.CharField(max_length=100),并将password字段设置为unique=True与类USERNAME_FIELD相同,字段需要有主键,否则会出现错误:AbstractUseridprimary_key=True

\n
from django.db import models\nfrom django.contrib.auth.models import AbstractBaseUser\n\nclass CustomUser(AbstractBaseUser):       # \xe2\x86\x93 Here \xe2\x86\x93\n    id = models.CharField(max_length=100, primary_key=True)\n    password = models.CharField(max_length=100, unique=True)\n    last_login = models.CharField(max_length=100)\n    \n    USERNAME_FIELD = \'password\'\n
Run Code Online (Sandbox Code Playgroud)\n

然后,运行以下命令:

\n
python manage.py makemigrations && python manage.py migrate\n
Run Code Online (Sandbox Code Playgroud)\n

然后,类的所有初始字段AbstractBaseUser都被更改,并将唯一约束设置为password字段,如下所示:

\n

在此输入图像描述

\n

接下来,通过设置删除password和字段,并仅设置一个现有字段,如下所示。*请记住,与 一样,即使设置为 ,字段也永远不会被删除,并且当将主键设置为 的字段时,它不需要具有唯一约束last_loginNoneidUSERNAME_FIELDAbstractUseridNoneidUSERNAME_FIELDunique=True

\n
from django.contrib.auth.models import AbstractBaseUser\n\nclass CustomUser(AbstractBaseUser):\n    password = None\n    last_login = None\n        \n    USERNAME_FIELD = \'id\'\n
Run Code Online (Sandbox Code Playgroud)\n

然后,运行以下命令:

\n
python manage.py makemigrations && python manage.py migrate\n
Run Code Online (Sandbox Code Playgroud)\n

然后,如下图所示,password并且last_login删除字段

\n

在此输入图像描述

\n

下面的代码是Github 上 Django 中的类的一部分AbstractBaseUser。可以看到已定义的字段、USERNAME_FIELD未定义的字段以及REQUIRED_FIELDS = []

\n
# "django/contrib/auth/base_user.py"\n\nclass AbstractBaseUser(models.Model):\n    password = models.CharField(_("password"), max_length=128)\n    last_login = models.DateTimeField(_("last login"), blank=True, null=True)\n\n    is_active = True\n\n    REQUIRED_FIELDS = []\n
Run Code Online (Sandbox Code Playgroud)\n

  • 这是一个很好的解释。看起来我可以使用 AbstractUser 进行所有自定义。那么AbstractBaseUser有什么用呢?请阐明这一点。 (2认同)

Piy*_*are 19

AbstractUser基本上只是您可能习惯使用的"用户"类.AbstractBaseUser做出的假设更少,您必须告诉它哪个字段代表用户名,需要哪些字段以及如何管理这些用户.

如果您只是向现有用户添加内容(即带有额外字段的配置文件数据),则使用AbstractUser,因为它更简单,更容易.如果您想重新考虑Django关于身份验证的一些假设,那么AbstractBaseUser将为您提供这样做的权力.

  • 您也可以告诉 AbstractUser 类使用哪个字段作为用户名。 (10认同)