Django中的AbstractUser vs AbstractBaseUser?

qoefvg9y  于 12个月前  发布在  Go
关注(0)|答案(5)|浏览(74)

AbstractUserAbstractBaseUser的用法看起来非常相似。

from django.contrib.auth.models import AbstractUser, AbstractBaseUser

字符串
这两者有什么区别?

um6iljoc

um6iljoc1#

文档对此作了充分的解释。AbstractUser是一个完整的User模型,包含字段,作为一个抽象类,以便您可以从中继承并添加您自己的配置文件字段和方法。AbstractBaseUser仅包含身份验证功能,但没有实际字段:你必须在子类的时候提供它们。

6ioyuze2

6ioyuze22#

AbstractUser基本上就是您可能已经习惯的“User”类。AbstractBaseUser的假设较少,您必须告诉它哪个字段代表用户名,哪些字段是必需的,以及如何管理这些用户。
如果你只是向现有用户添加内容(即使用额外字段的配置文件数据),然后使用AbstractUser,因为它更简单、更容易。如果你想重新考虑Django关于身份验证的一些假设,那么AbstractBaseUser就可以让你这样做。

gc0ot86w

gc0ot86w3#

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

<AbstractUser>

AbstractUser类最初有11个字段与默认用户类(型号)相同,如下所示,对于AbstractUser类的子类,您可以添加新字段,更改和删除初始字段。* 请注意AbstractUser类的初始字段中的usernameemail字段是特殊的,只有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) class,如下所示:

# "account/models.py"

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    pass


然后,运行下面的命令:

python manage.py makemigrations && python manage.py migrate


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


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

# "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类的初始字段创建agegender字段,如下所示:



接下来,通过设置models.CharField(max_length=100)来更改AbstractUser类的所有初始字段,但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设置为passwordlast_loginis_superuserusername来删除这些字段,如下所示。* 请记住,即使设置Noneid字段也永远不能被删除,并且USERNAME_FIELD必须有一个现有字段,默认情况下,具有唯一约束username字段被设置为USERNAME_FIELD,所以如果通过设置None来删除username字段,你还需要删除username字段从USERNAME_FIELD通过设置一个现有的字段如下所示否则有一个错误所以在下面的这个例子中,有7个现有的字段idfirst_namelast_nameemailis_staffis_activedate_joined,因此通过将last_name字段与unique=True设置为USERNAME_FIELD,将USERNAME_FIELDusername字段更改为last_name字段,如下所示。* 请记住,与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


然后,如下图所示,删除passwordlast_loginis_superuserusername字段,last_name字段有Unique Constraint



接下来,再次删除passwordlast_loginis_superuserusername字段,如下所示,但这次,通过将email字段与unique=True设置为USERNAME_FIELD,将USERNAME_FIELD字段从username字段更改为email字段,如下所示。* 请记住,默认情况下,email字段也设置为REQUIRED_FIELDS,不允许同时将同一字段设置为USERNAME_FIELDREQUIRED_FIELDS,否则会出现错误,请将no字段设置为REQUIRED_FIELDS,如下所示。* 请记住,没有字段设置为REQUIRED_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


然后,如下图所示,passwordlast_loginis_superuserusername字段被删除,email字段具有唯一约束



下面的代码是Github上Django中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>

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

id
password
last_login


现在,将password字段与unique=True设置为USERNAME_FIELD类中的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


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



接下来,为CustomUser(AbstractBaseUser)类设置agegender字段,并将age字段与unique=True设置为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类的初始字段创建agegender字段,并将Unique Constraint设置为age字段,如下所示:


接下来,通过设置models.CharField(max_length=100)来更改AbstractBaseUser类的所有初始字段,并将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类的所有初始字段,将Unique Constraint设置为password字段,如下图所示:



接下来,通过将None设置为passwordlast_login来删除它们,并仅将一个现有字段id设置为USERNAME_FIELD,如下所示。* 请注意,与AbstractUser相同,id字段永远不会被删除,即使将None设置为id,当将具有Primary Keyid字段设置为USERNAME_FIELD时,不需要unique=True具有Unique Constraint

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


然后,如下所示,删除passwordlast_login字段:



下面的代码是Github上Django中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 = []
1u4esq0p

1u4esq0p4#

AbstractUser类是AbstractBaseUser和PermissionsMixin类的子类,AbstractUser类有11个字段,与默认User类(模型)相同,如下所示:

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 class是AbstractUser的超类,PermissionsMixin class有2个字段,如下所示:

id
is_superuser

  • 您可以看到我的答案,解释如何使用AbstractUserAbstractBaseUserPermissionsMixin设置电子邮件和密码身份验证。
nkcskrwz

nkcskrwz5#

主要区别主要在于Usecase。例如,你不再需要Django提供的现有User类,你只关心User类和你自己的自定义字段提供的身份验证功能。在这种情况下,您应该使用AbstractBaseUser。在另一种情况下,您希望使用现有的用户字段和功能,但在此基础上,您希望添加一些额外的字段和方法。在这种情况下,您应该使用AbstractUser。

相关问题