Django附带的身份验证对于大多数常见情况来说已经足够好了,但是开箱即用的默认值可能还没有满足您的需求。在项目中定制身份验证需要了解所提供系统的哪些点是可扩展或可替换的。此文档提供有关如何自定义身份验证系统的详细信息。
Authentication backends 当用户模型中存储的用户名和密码需要针对不同于Django默认值的服务进行身份验证时,提供一个可扩展系统。
你可以给你的模型 custom permissions 可以通过Django的授权系统进行检查。
你可以 extend 默认值 User
模型,或 substitute 完全定制的模型。
有时您可能需要连接到另一个身份验证源——也就是用户名、密码或身份验证方法的另一个源。
例如,您的公司可能已经有一个LDAP设置,用于存储每个员工的用户名和密码。如果用户在LDAP和基于Django的应用程序中拥有单独的帐户,那么对网络管理员和用户本身来说都是一个麻烦。
因此,为了处理这种情况,Django身份验证系统允许您插入其他身份验证源。您可以覆盖Django的默认基于数据库的方案,也可以与其他系统一起使用默认系统。
见 authentication backend reference 有关Django所包含的身份验证后端的信息。
在幕后,Django维护了一个“身份验证后端”列表,用于检查身份验证。当有人调用时 django.contrib.auth.authenticate()
--如中所述 How to log a user in --Django尝试在其所有身份验证后端进行身份验证。如果第一个身份验证方法失败,Django将尝试第二个方法,依此类推,直到尝试了所有后端。
要使用的身份验证后端列表在 AUTHENTICATION_BACKENDS
设置。这应该是一个python路径名列表,指向知道如何进行身份验证的python类。这些类可以在您的python路径上的任何地方。
默认情况下, AUTHENTICATION_BACKENDS
设置为:
["django.contrib.auth.backends.ModelBackend"]
这是检查Django用户数据库并查询内置权限的基本身份验证后端。它不通过任何速率限制机制提供针对暴力攻击的保护。您可以在自定义身份验证后台实现自己的速率限制机制,也可以使用大多数Web服务器提供的机制。
秩序 AUTHENTICATION_BACKENDS
重要的是,如果相同的用户名和密码在多个后端中有效,Django将在第一个正匹配时停止处理。
如果后端引发 PermissionDenied
异常,身份验证将立即失败。Django不会检查后面的后端。
备注
一旦用户通过了身份验证,Django就会存储在用户会话中使用哪个后端对用户进行身份验证,并在需要访问当前经过身份验证的用户时,在该会话期间重复使用相同的后端。这实际上意味着在每个会话的基础上缓存身份验证源,因此如果您更改 AUTHENTICATION_BACKENDS
如果需要强制用户使用不同的方法重新进行身份验证,则需要清除会话数据。要做到这一点,一个简单的方法是执行 Session.objects.all().delete()
。
身份验证后端是实现两个必需方法的类: get_user(user_id)
和 authenticate(request, **credentials)
以及一组与权限相关的可选权限 authorization methods .
这个 get_user
方法采用 user_id
--它可以是用户名、数据库ID或其他,但必须是用户对象的主键,并返回用户对象或 None
.
这个 authenticate
方法接受一个 request
参数和凭证作为关键字参数。大多数时候,它看起来是这样的::
from django.contrib.auth.backends import BaseBackend
class MyBackend(BaseBackend):
def authenticate(self, request, username=None, password=None):
# Check the username/password and return a user.
...
但它也可以对令牌进行身份验证,比如:
from django.contrib.auth.backends import BaseBackend
class MyBackend(BaseBackend):
def authenticate(self, request, token=None):
# Check the token and return a user.
...
不管怎样, authenticate()
应该检查它获取的凭据,如果凭据有效,则返回与这些凭据匹配的用户对象。如果它们无效,它应该返回 None
.
request
是一个 HttpRequest
可能是 None
如果没有提供给 authenticate()
(将其传递到后端)。
django管理与django紧密耦合 User object . 解决这个问题的最佳方法是创建一个Django User
对象对于存在于后端的每个用户(例如,在LDAP目录、外部SQL数据库等中),您可以提前编写一个脚本来执行此操作,或者 authenticate
方法可以在用户第一次登录时执行。
下面是一个后端示例,它根据您的 settings.py
文件并创建django User
对象第一次用户身份验证时:
from django.conf import settings
from django.contrib.auth.backends import BaseBackend
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User
class SettingsBackend(BaseBackend):
"""
Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.
Use the login name and a hash of the password. For example:
ADMIN_LOGIN = 'admin'
ADMIN_PASSWORD = 'pbkdf2_sha256$30000$Vo0VlMnkR4Bk$qEvtdyZRWTcOsCnI/oQ7fVOu1XAURIZYoOZ3iq8Dr4M='
"""
def authenticate(self, request, username=None, password=None):
login_valid = settings.ADMIN_LOGIN == username
pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
if login_valid and pwd_valid:
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
# Create a new user. There's no need to set a password
# because only the password from settings.py is checked.
user = User(username=username)
user.is_staff = True
user.is_superuser = True
user.save()
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
若要为给定模型对象创建自定义权限,请使用 permissions
model Meta attribute .
这个例子 Task
模型创建两个自定义权限,即用户可以或不能使用的操作 Task
特定于应用程序的实例:
class Task(models.Model):
...
class Meta:
permissions = [
("change_task_status", "Can change the status of tasks"),
("close_task", "Can remove a task by setting its status as closed"),
]
唯一能做的就是在运行时创建那些额外的权限 manage.py migrate
(创建权限的函数连接到 post_migrate
信号)。当用户试图访问应用程序提供的功能(更改任务的状态或关闭任务)时,代码负责检查这些权限的值。继续上述示例,下面检查用户是否可以关闭任务:
user.has_perm("app.close_task")
User
模型¶有两种方法可以扩展默认值 User
模型,而不替换您自己的模型。如果所需的更改纯粹是行为性的,并且不需要对数据库中存储的内容进行任何更改,则可以创建一个 proxy model 基于 User
. 这允许代理模型提供的任何功能,包括默认排序、自定义管理器或自定义模型方法。
如果您希望存储与 User
,可以使用 OneToOneField
到包含字段以获取附加信息的模型。这种一对一的模型通常被称为配置文件模型,因为它可能存储有关站点用户的非身份验证相关信息。例如,您可以创建一个员工模型:
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(max_length=100)
假设现有员工Fred Smith同时具有用户和员工模型,您可以使用Django的标准相关模型约定访问相关信息:
>>> u = User.objects.get(username="fsmith")
>>> freds_department = u.employee.department
要将配置文件模型的字段添加到管理员的用户页,请定义 InlineModelAdmin
(对于这个示例,我们将使用 StackedInline
在你的应用程序中 admin.py
并将其添加到 UserAdmin
在中注册的类 User
类:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import Employee
# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class EmployeeInline(admin.StackedInline):
model = Employee
can_delete = False
verbose_name_plural = "employee"
# Define a new User admin
class UserAdmin(BaseUserAdmin):
inlines = [EmployeeInline]
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
这些配置文件模型在任何方面都不是特别的——它们只是刚好与用户模型有一对一链接的django模型。因此,它们不是在创建用户时自动创建的,而是 django.db.models.signals.post_save
可用于根据需要创建或更新相关模型。
使用相关模型会导致额外的查询或联接来检索相关数据。根据需要,包含相关字段的自定义用户模型可能是更好的选择,但是,与项目应用程序中默认用户模型的现有关系可能会证明额外的数据库负载是合理的。
User
模型¶有些项目可能有Django内置的身份验证要求 User
模型并不总是合适的。例如,在某些站点上,使用电子邮件地址作为标识令牌而不是用户名更有意义。
Django允许您通过为 AUTH_USER_MODEL
引用自定义模型的设置:
AUTH_USER_MODEL = "myapp.MyUser"
这个虚线对描述了 label
Django应用程序(它必须位于您的 INSTALLED_APPS
),以及您希望用作用户模型的Django模型的名称。
如果您正在启动一个新项目,强烈建议您设置自定义用户模型,即使是默认的 User
模型对你来说足够了。此模型的行为与默认用户模型相同,但如果需要,您将来可以对其进行自定义:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
别忘了指出 AUTH_USER_MODEL
对它。在创建任何迁移或运行之前执行此操作 manage.py migrate
第一次。
另外,在应用程序中注册模型 admin.py
::
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User
admin.site.register(User, UserAdmin)
改变 AUTH_USER_MODEL
例如,创建数据库表之后,由于它会影响外键和多对多关系,所以要困难得多。
此更改无法自动完成,需要手动修复架构、从旧用户表中移动数据,以及可能手动重新应用某些迁移。见 #25313 以获取步骤的大纲。
由于Django对可交换模型的动态依赖特性的限制,该模型被 AUTH_USER_MODEL
必须在应用程序的第一次迁移中创建(通常称为 0001_initial
)否则,您将出现依赖关系问题。
此外,您可能会遇到 CircularDependencyError
当以django的身份运行迁移时,由于动态依赖关系,将无法自动中断依赖循环。如果看到此错误,则应通过将用户模型所依赖的模型移动到第二个迁移中来中断循环。(您可以尝试制作两个具有 ForeignKey
彼此之间,看看如何 makemigrations
如果您想了解循环依赖的一般情况,请解析它。)
AUTH_USER_MODEL
¶可重用应用程序不应该实现自定义用户模型。一个项目可能使用许多应用程序,而实现自定义用户模型的两个可重用应用程序不能一起使用。如果需要在应用程序中存储每个用户的信息,请使用 ForeignKey
或 OneToOneField
到 settings.AUTH_USER_MODEL
如下所述。
User
模型¶如果你提到 User
直接(例如,通过在外键中引用它),您的代码将不适用于 AUTH_USER_MODEL
设置已更改为其他用户模型。
而不是指 User
直接,您应该使用 django.contrib.auth.get_user_model()
. 此方法将返回当前活动的用户模型——如果指定了自定义用户模型,则返回自定义用户模型;或者 User
否则。
定义外键或与用户模型的多对多关系时,应使用 AUTH_USER_MODEL
设置。例如::
from django.conf import settings
from django.db import models
class Article(models.Model):
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
当连接到用户模型发送的信号时,应使用 AUTH_USER_MODEL
设置。例如::
from django.conf import settings
from django.db.models.signals import post_save
def post_save_receiver(sender, instance, created, **kwargs):
pass
post_save.connect(post_save_receiver, sender=settings.AUTH_USER_MODEL)
一般来说,使用 AUTH_USER_MODEL
但是,在导入时执行的代码中设置,也可以调用 get_user_model()
当Django正在导入模型时,您可以使用 models.ForeignKey(get_user_model(), ...)
.
如果您的应用程序使用多个用户模型进行测试,请使用 @override_settings(AUTH_USER_MODEL=...)
例如,您缓存 get_user_model()
在模块级变量中,您可能需要 setting_changed
清除缓存的信号。例如::
from django.apps import apps
from django.contrib.auth import get_user_model
from django.core.signals import setting_changed
from django.dispatch import receiver
@receiver(setting_changed)
def user_model_swapped(*, setting, **kwargs):
if setting == "AUTH_USER_MODEL":
apps.clear_cache()
from myapp import some_module
some_module.UserModel = get_user_model()
使用自定义用户模型启动项目时,请停止考虑这是否是项目的正确选择。
将所有与用户相关的信息保存在一个模型中,就不需要进行其他或更复杂的数据库查询来检索相关的模型。另一方面,它可能更适合将特定于应用程序的用户信息存储在与自定义用户模型有关系的模型中。这样,每个应用程序就可以指定自己的用户数据需求,而不会与其他应用程序的假设产生潜在的冲突或破坏。它还意味着您将尽可能地保持您的用户模型的简单性,将重点放在身份验证上,并遵循Django希望自定义用户模型能够满足的最低要求。
如果您使用默认的认证后端,那么您的模型必须有一个唯一的字段,可以用于标识目的。这可以是用户名、电子邮件地址或任何其他唯一属性。如果使用可以支持的自定义身份验证后端,则允许使用非唯一的用户名字段。
构造兼容自定义用户模型的最简单方法是从继承 AbstractBaseUser
. AbstractBaseUser
提供用户模型的核心实现,包括哈希密码和标记化密码重置。然后必须提供一些关键的实现细节:
一个字符串,描述用作唯一标识符的用户模型上的字段的名称。这通常是某种类型的用户名,但也可以是电子邮件地址或任何其他唯一标识符。田野 must 独一无二的(例如 unique=True
在其定义中设置),除非您使用可以支持非唯一用户名的自定义身份验证后端。
在下面的示例中,字段 identifier
用作标识字段:
class MyUser(AbstractBaseUser):
identifier = models.CharField(max_length=40, unique=True)
...
USERNAME_FIELD = "identifier"
描述电子邮件字段名称的字符串 User
模型。此值由返回 get_email_field_name()
.
当通过创建用户时将提示输入的字段名列表。 createsuperuser
管理命令。将提示用户为每个字段提供一个值。它必须包括 blank
是 False
或者未定义,并且可能包括需要在交互创建用户时提示的其他字段。 REQUIRED_FIELDS
在Django的其他部分没有效果,比如在admin中创建用户。
例如,下面是用户模型的部分定义,它定义了两个必需字段-出生日期和身高:
class MyUser(AbstractBaseUser):
...
date_of_birth = models.DateField()
height = models.FloatField()
...
REQUIRED_FIELDS = ["date_of_birth", "height"]
备注
REQUIRED_FIELDS
必须包含用户模型上的所有必需字段,但应该 not 包含 USERNAME_FIELD
或 password
因为这些字段总是会被提示输入。
指示用户是否被视为“活动”的布尔属性。此属性作为上的属性提供 AbstractBaseUser
拖欠 True
. 您选择如何实现它将取决于所选认证后端的详细信息。参见 is_active attribute on the built-in user model
有关详细信息。
可选的。用户的较长形式标识符,如全名。如果实现,它将出现在对象历史记录中的用户名旁边。 django.contrib.admin
.
可选的。用户的简短非正式标识符,如他们的名字。如果实现,则将替换标题中的用户问候语中的用户名。 django.contrib.admin
.
进口 AbstractBaseUser
AbstractBaseUser
和 BaseUserManager
可从导入 django.contrib.auth.base_user
以便进口时不包括 django.contrib.auth
在里面 INSTALLED_APPS
.
以下属性和方法可用于 AbstractBaseUser
:
返回由指定的字段的值 USERNAME_FIELD
.
通过调用规范化用户名 normalize_username()
. 如果重写此方法,请确保调用 super()
保持正常化。
返回由指定的电子邮件字段的名称 EMAIL_FIELD
属性。默认为 'email'
如果 EMAIL_FIELD
未指定。
将NFKC Unicode规范化应用于用户名,以便将具有不同Unicode代码点的视觉相同字符视为相同。
只读属性 True
(而不是 AnonymousUser.is_authenticated
总是这样 False
)这是一种判断用户是否已通过身份验证的方法。这并不意味着任何权限,也不检查用户是否处于活动状态或是否具有有效会话。即使正常情况下您将在 request.user
以确定它是否由 AuthenticationMiddleware
(表示当前登录的用户),您应该知道该属性是 True
对于任何 User
实例。
只读属性 False
. 这是一种区分 User
和 AnonymousUser
对象。一般来说,您应该更喜欢使用 is_authenticated
到这个属性。
将用户密码设置为给定的原始字符串,注意密码散列。不保存 AbstractBaseUser
对象。
当原始密码为 None
,密码将设置为不可用的密码,就像 set_unusable_password()
使用。
Asynchronous version : acheck_password()
返回 True
如果给定的原始字符串是用户的正确密码。(这将在进行比较时考虑密码散列。)
将用户标记为未设置密码。这与密码的空字符串不同。 check_password()
因为这个用户永远不会回来 True
. 不保存 AbstractBaseUser
对象。
如果应用程序针对现有外部源(如LDAP目录)进行身份验证,则可能需要这样做。
返回 False
如果 set_unusable_password()
已为此用户调用。
使用生成密码字段的HMAC SECRET_KEY_FALLBACKS
。使用者 get_user()
。
AbstractUser
子类 AbstractBaseUser
:
通过调用规范电子邮件 BaseUserManager.normalize_email()
. 如果重写此方法,请确保调用 super()
保持正常化。
您还应该为您的用户模型定义自定义管理器。如果您的用户模型定义 username
, email
, is_staff
, is_active
, is_superuser
, last_login
,以及 date_joined
字段与Django的默认用户相同,您可以安装Django的 UserManager
;但是,如果您的用户模型定义了不同的字段,则您需要定义一个扩展的自定义管理器 BaseUserManager
提供两种额外方法:
的原型 create_user()
应该接受用户名字段,加上所有必需的字段作为参数。例如,如果用户模型使用 email
作为用户名字段,并且 date_of_birth
作为必需字段,然后 create_user
应定义为:
def create_user(self, email, date_of_birth, password=None):
# create user here
...
的原型 create_superuser()
应该接受用户名字段,加上所有必需的字段作为参数。例如,如果用户模型使用 email
作为用户名字段,并且 date_of_birth
作为必需字段,然后 create_superuser
应定义为:
def create_superuser(self, email, date_of_birth, password=None):
# create superuser here
...
对于一个 ForeignKey
在里面 USERNAME_FIELD
或 REQUIRED_FIELDS
,这些方法接收 to_field
(the primary_key
默认情况下)。
BaseUserManager
提供以下实用方法:
User
¶如果你对Django的 User
模型,但是您想要添加一些附加的配置文件信息,您可以子类 django.contrib.auth.models.AbstractUser
并添加您的自定义配置文件字段,尽管我们建议使用单独的模型,如中所述 指定自定义用户模型 。 AbstractUser
提供默认设置的完整实现。 User
作为一个 abstract model 。
Django的内置 forms 和 views 对他们正在使用的用户模型进行某些假设。
以下表单与的任何子类都兼容 AbstractBaseUser
:
AuthenticationForm
:使用由指定的用户名字段 USERNAME_FIELD
.
以下表单对用户模型进行假设,如果满足这些假设,则可以按原样使用:
PasswordResetForm
:假设用户模型具有一个字段,该字段存储用户的电子邮件地址,该地址的名称由返回 get_email_field_name()
(email
默认情况下)可用于标识用户和名为 is_active
防止非活动用户重置密码。
最后,以下表格与 User
需要重写或扩展以使用自定义用户模型:
如果您的自定义用户模型是 AbstractUser
,那么您可以以这种方式扩展这些表单::
from django.contrib.auth.forms import UserCreationForm
from myapp.models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = UserCreationForm.Meta.fields + ("custom_field",)
django.contrib.admin
¶如果希望自定义用户模型也与管理员一起工作,则用户模型必须定义一些其他属性和方法。这些方法允许管理员控制用户对管理内容的访问:
返回 True
如果允许用户访问管理站点。
返回 True
如果用户帐户当前处于活动状态。
返回 True
如果用户具有命名权限。如果 obj
如果提供,则需要根据特定对象实例检查权限。
返回 True
如果用户有权访问给定应用程序中的模型。
您还需要向管理员注册您的自定义用户模型。如果自定义用户模型扩展 django.contrib.auth.models.AbstractUser
,您可以使用Django现有的 django.contrib.auth.admin.UserAdmin
类。但是,如果您的用户模型扩展 AbstractBaseUser
,您需要定义一个自定义 ModelAdmin
类。可以将默认值子类化 django.contrib.auth.admin.UserAdmin
;但是,您需要重写引用上字段的任何定义。 django.contrib.auth.models.AbstractUser
这不在您的自定义用户类中。
备注
如果使用的是自定义 ModelAdmin
这是 django.contrib.auth.admin.UserAdmin
,然后您需要将自定义字段添加到 fieldsets
(for用于编辑用户的字段)和 add_fieldsets
(for创建用户时使用的字段)。例如::
from django.contrib.auth.admin import UserAdmin
class CustomUserAdmin(UserAdmin):
...
fieldsets = UserAdmin.fieldsets + ((None, {"fields": ["custom_field"]}),)
add_fieldsets = UserAdmin.add_fieldsets + ((None, {"fields": ["custom_field"]}),)
看见 a full example 了解更多详细信息。
为了方便将django的权限框架包含到您自己的用户类中,django提供了 PermissionsMixin
. 这是一个抽象模型,可以包含在用户模型的类层次结构中,为您提供支持Django权限模型所需的所有方法和数据库字段。
PermissionsMixin
提供以下方法和属性:
布尔函数。指定此用户具有所有权限,而不显式分配这些权限。
返回用户直接拥有的一组权限字符串。
如果 obj
传递,仅返回该特定对象的用户权限。
返回用户通过其组拥有的一组权限字符串。
如果 obj
传入,仅返回此特定对象的组权限。
返回用户通过组和用户权限拥有的一组权限字符串。
如果 obj
传入,仅返回此特定对象的权限。
返回 True
如果用户具有指定的权限,其中 perm
格式为 "<app label>.<permission codename>"
(见 permissions )如果 User.is_active
和 is_superuser
都是 True
,此方法始终返回 True
.
如果 obj
如果传入,此方法将不会检查模型的权限,而是检查此特定对象的权限。
返回 True
如果用户具有每个指定的权限,则每个权限的格式为 "<app label>.<permission codename>"
.如果 User.is_active
和 is_superuser
都是 True
,此方法始终返回 True
.
如果 obj
如果传入,此方法将不会检查模型的权限,而是检查特定对象的权限。
返回 True
如果用户在给定包(django app标签)中有任何权限。如果 User.is_active
和 is_superuser
都是 True
,此方法始终返回 True
.
自定义用户模型的一个限制是,安装自定义用户模型将破坏任何代理模型扩展 User
. 代理模型必须基于具体的基类;通过定义自定义的用户模型,可以消除Django可靠地标识基类的能力。
如果项目使用代理模型,则必须修改代理以扩展项目中使用的用户模型,或者将代理的行为合并到 User
子类。
这是一个符合管理员规范的自定义用户应用程序的示例。该用户模型使用电子邮件地址作为用户名,并具有所需的出生日期;除了 admin
用户帐户上的标志。该模型将与所有内置的授权表单和视图兼容,用户创建表单除外。此示例说明了大多数组件如何协同工作,但无意直接复制到项目中以供生产使用。
此代码将全部存在于 models.py
自定义身份验证应用程序的文件::
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
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
def create_superuser(self, email, date_of_birth, password=None):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user = self.create_user(
email,
password=password,
date_of_birth=date_of_birth,
)
user.is_admin = True
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
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
@property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
然后,要向Django的管理员注册此自定义用户模型,应用程序的 admin.py
文件::
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
from django.core.exceptions import ValidationError
from customauth.models import MyUser
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 ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
disabled password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = MyUser
fields = ["email", "password", "date_of_birth", "is_active", "is_admin"]
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserChangeForm
add_form = UserCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ["email", "date_of_birth", "is_admin"]
list_filter = ["is_admin"]
fieldsets = [
(None, {"fields": ["email", "password"]}),
("Personal info", {"fields": ["date_of_birth"]}),
("Permissions", {"fields": ["is_admin"]}),
]
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = [
(
None,
{
"classes": ["wide"],
"fields": ["email", "date_of_birth", "password1", "password2"],
},
),
]
search_fields = ["email"]
ordering = ["email"]
filter_horizontal = []
# Now register the new UserAdmin...
admin.site.register(MyUser, UserAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)
最后,使用 AUTH_USER_MODEL
设置在你的 settings.py
::
AUTH_USER_MODEL = "customauth.MyUser"
7月 22, 2024