Django2.0官方文档学习-自定义认证

Django2.0官方文档学习-自定义认证

The authentication that comes with Django is good enough for most
common cases, but you may have needs not met by the out-of-the-box
defaults. To customize authentication to your projects involves
understanding what points of the provided system are extensible or
replaceable. This document provides details about how the auth system
can be customized.

大多数情况下,django的认证模块满足需求,但是你也可能有一些超越django框架的需求。如果你的项目需要自定义认证功能,需要了解系统中哪些模块需要拓展或者替代。本文档提供了认证系统自定义(定制)的具体细节。

Authentication backends provide an extensible system for when a
username and password stored with the user model need to be
authenticated against a different service than Django’s default.

当一个非django默认的服务需要使用用户名密码对user模型进行认证时,后端认证提供了一个可拓展系统。

You can give your models custom permissions that can be checked
through Django’s authorization system.

你可以给你的模型自定义一些许可,当django的认证系统进行认证时,进行同步检测。

You can extend the default User model, or substitute a completely
customized model.

你可以拓展默认的User模型,或者使用一个完整的模型替换User模型

Other authentication sources¶

其他认证来源

There may be times you have the need to hook into another
authentication source – that is, another source of usernames and
passwords or authentication methods.

有时候你需要在认证时,使用其他来源的用户名、密码数据进行认证。

For example, your company may already have an LDAP setup that stores a
username and password for every employee. It’d be a hassle for both
the network administrator and the users themselves if users had
separate accounts in LDAP and the Django-based applications.

例如:你的公司可能已经有了一个LDAP轻量级用户访问模式,为每一个职工存储了用户名和密码。对于管理员和用户来说,如果同时存在LDAP和django应用的两套密码,是一件很麻烦的事情。

So, to handle situations like this, the Django authentication system
lets you plug in other authentication sources. You can override
Django’s default database-based scheme, or you can use the default
system in tandem with other systems.

所以,处理上述情形时,django认证系统允许你配置其他的认证源。你可以覆盖django默认的基于数据库的机制或者你也可以使用django默认的认证系统,同时串联如其他认证系统。

See the authentication backend reference for information on the
authentication backends included with Django.

点击链接,查阅后端认证参考信息。

Specifying authentication backends¶

指定认证后端

Behind the scenes, Django maintains a list of “authentication
backends” that it checks for authentication. When somebody calls
django.contrib.auth.authenticate() – as described in How to log a user
in – Django tries authenticating across all of its authentication
backends. If the first authentication method fails, Django tries the
second one, and so on, until all backends have been attempted.

本质上,django包含了一个认证后端的列表。当某用户触发django.contrib.auth.authenticate()时,比如用户登录时,django将会轮询所有后端认证模块,如果第一个后端认证即失败,则django会尝试第二个,第三个······,直至尝试所有后端认证方法。

The list of authentication backends to use is specified in the
AUTHENTICATION_BACKENDS setting. This should be a list of Python path
names that point to Python classes that know how to authenticate.
These classes can be anywhere on your Python path.

认证后端列表在settings.py的AUTHENTICATION_BACKENDS标签中指定。且必须是一个python路径名,以指定认证的python类。这个类可以在python的路径中的任意位置。

By default, AUTHENTICATION_BACKENDS is set to:

默认情况下,AUTHENTICATION_BACKENDS设置为:

[‘django.contrib.auth.backends.ModelBackend’] That’s the basic
authentication backend that checks the Django users database and
queries the built-in permissions. It does not provide protection
against brute force attacks via any rate limiting mechanism. You may
either implement your own rate limiting mechanism in a custom auth
backend, or use the mechanisms provided by most Web servers.

[‘django.contrib.auth.backends.ModelBackend’]
这是最基本的认证后端,检查django用户数据库及请求内置许可。它不提供基于速率限制机制的暴力攻击防护。
你可以自行实现速率限制机制后端或者使用大多数网络服务器附带提供的此项功能。

The order of AUTHENTICATION_BACKENDS matters, so if the same username
and password is valid in multiple backends, Django will stop
processing at the first positive match.

后端认证处理顺序是:如果同一个用户名密码在多个认证后端模块都能够通过认证,则django会在第一个认证通过时停止后续后端模块的认证。

If a backend raises a PermissionDenied exception, authentication will
immediately fail. Django won’t check the backends that follow.

如果一个后端认证模块返回许可拒绝异常,则认证立即失效,django不会再检查后续的认证模块。

Note

注意

Once a user has authenticated, Django stores which backend was used to
authenticate the user in the user’s session, and re-uses the same
backend for the duration of that session whenever access to the
currently authenticated user is needed. This effectively means that
authentication sources are cached on a per-session basis, so if you
change AUTHENTICATION_BACKENDS, you’ll need to clear out session data
if you need to force users to re-authenticate using different methods.
A simple way to do that is simply to execute
Session.objects.all().delete().

一旦一个用户通过了认证,django会在该用户的session中存储通过该用户认证的是哪个认证后端,并且在该session存续期内,如果还需要对该用户进行一些特定的认证,则会再次使用该认证后端进行认证。这实际上意味着认证源在每一个session中都进行了缓存,所以,如果你改变了认证后端,你将必须清空session数据以迫使用户使用其他认证方法进行再次认证。可以采用一个简单的方法进行清空:>>>Session.objects.al().delete()

Writing an authentication backend¶

编写认证后端

An authentication backend is a class that implements two required
methods: get_user(user_id) and authenticate(request, **credentials),
as well as a set of optional permission related authorization methods.

认证后端是一个类,该类实现了两个必须的方法:get_user(user_di)和authenticate(request,**credetials)

The get_user method takes a user_id – which could be a username,
database ID or whatever, but has to be the primary key of your user
object – and returns a user object.

get_user方法传入一个用户id,可以是一个用户名或者数据库id或其他任意参数,但是必须是用户对象模型的一个主键,该方法返回用户模型的对象。

The authenticate method takes a request argument and credentials as
keyword arguments. Most of the time, it’ll just look like this:

authenticate方法传入一个request请求和一系列关键字形式的认证参数,多数情况下如下:

class MyBackend:
    def authenticate(self, request, username=None, password=None):
        # Check the username/password and return a user.
        ...

But it could also authenticate a token, like so:

有时也可以是使用一个token,如下:

class MyBackend:
    def authenticate(self, request, token=None):
        # Check the token and return a user.
        ...

Either way, authenticate() should check the credentials it gets and
return a user object that matches those credentials if the credentials
are valid. If they’re not valid, it should return None.

上述两种方法,authenticate()都会检查认证参数,如果认证成功则返回一个用户模型对象,如果不成功则返回None。

request is an HttpRequest and may be None if it wasn’t provided to
authenticate() (which passes it on to the backend).

request是一个HttpRequest,如果没有向authentic()提供request,则会返回None。

The Django admin is tightly coupled to the Django User object. The
best way to deal with this is to create a Django User object for each
user that exists for your backend (e.g., in your LDAP directory, your
external SQL database, etc.) You can either write a script to do this
in advance, or your authenticate method can do it the first time a
user logs in.

django管理模块admin与django用户对象紧密结合,处理此情形的最好的方法是为每一个已经在你的后端(如LDAP目录或者外部sql数据库)已经存在的用户创建一个django用户对象,你可以写一个脚本进行操作或者编写一个认证方法在用户首次登陆时进行操作。

Here’s an example backend that authenticates against a username and
password variable defined in your settings.py file and creates a
Django User object the first time a user authenticates:

这里是一个例子:后端认证一个在settings.py中定义的用户名密码变量,并且在用户首次认证时创建一个django用户对象

from django.conf import settings
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User

class SettingsBackend:
    """
    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

Changed in Django 1.11: The request parameter was added to
authenticate() and support for backends that don’t accept it will be
removed in Django 2.1.

Django1.11中的变化:request参数加入了authenticate(),并且支持后端。在django2.1中后端将不支持reuqest,因此将会被移除。

Handling authorization in custom backends¶

自定义后端处理认证

Custom auth backends can provide their own permissions.

自定义的后端认证能够提供它们相应的自定义许可。

The user model will delegate permission lookup functions
(get_group_permissions(), get_all_permissions(), has_perm(), and
has_module_perms()) to any authentication backend that implements
these functions.

用户模型将面向所有认证后端代理这些后端实现的许可查询的相关功能:get_group_permissions(),get_all_permissions(),has_perm()及has_module_perms()。

The permissions given to the user will be the superset of all
permissions returned by all backends. That is, Django grants a
permission to a user that any one backend grants.

给与用户的许可是所有后端许可的一个超集。也就是说,任意一个认证后端向用户的许可都经由django进行对外授权。

If a backend raises a PermissionDenied exception in has_perm() or
has_module_perms(), the authorization will immediately fail and Django
won’t check the backends that follow.

如果一个后端在has_perm()或者has_module_perms()中返回的拒绝许可异常,认证系统会立即返回失败,django将不会再向后续的其他认证后端调用查询请求。

The simple backend above could implement permissions for the magic
admin fairly simply:

上述实现相当简单:

class SettingsBackend:
    ...
    def has_perm(self, user_obj, perm, obj=None):
        return user_obj.username == settings.ADMIN_LOGIN

This gives full permissions to the user granted access in the above
example. Notice that in addition to the same arguments given to the
associated django.contrib.auth.models.User functions, the backend auth
functions all take the user object, which may be an anonymous user, as
an argument.

上述例子给与了用户所有的许可权限。注意,在django.contrib.auth.models.User功能中,后端认证功能所用的参数是用户对象,该用户对象允许使用一个匿名的对象。

A full authorization implementation can be found in the ModelBackend
class in django/contrib/auth/backends.py, which is the default backend
and queries the auth_permission table most of the time. If you wish to
provide custom behavior for only part of the backend API, you can take
advantage of Python inheritance and subclass ModelBackend instead of
implementing the complete API in a custom backend.

可以在django/contrib/auth/backends.py中的ModelBackend 类中查看一个完整的用户认证实现方法

Authorization for anonymous users¶

匿名认证

An anonymous user is one that is not authenticated i.e. they have
provided no valid authentication details. However, that does not
necessarily mean they are not authorized to do anything. At the most
basic level, most websites authorize anonymous users to browse most of
the site, and many allow anonymous posting of comments etc.

匿名用户是一个没有经过认证的用户。例如他们没有提供足够的认证信息。但是,这并不代表了这些匿名用户就不能进行一些操作。在多数基本的情况下,大多数网站的匿名认证用户允许浏览网站大多数页面,并且许多网站也允许匿名用户发表跟帖评论(朝鲜除外)

Django’s permission framework does not have a place to store
permissions for anonymous users. However, the user object passed to an
authentication backend may be an
django.contrib.auth.models.AnonymousUser object, allowing the backend
to specify custom authorization behavior for anonymous users. This is
especially useful for the authors of re-usable apps, who can delegate
all questions of authorization to the auth backend, rather than
needing settings, for example, to control anonymous access.

django的许可框架并不存储匿名用户的许可。但是,通过后端认证的用户对象可能是一个django.contrib.auth.modelsAnonymnousUser对象,允许后端实现一些针对匿名用户的自定义认证行为。相比于使用settings去控制匿名用户的访问,这在一些复用应用,如代理所有的认证问题时显得相当有用。

Authorization for inactive users¶

非激活用户的认证

An inactive user is one that has its is_active field set to False. The
ModelBackend and RemoteUserBackend authentication backends prohibits
these users from authenticating. If a custom user model doesn’t have
an is_active field, all users will be allowed to authenticate.

非激活用户在模型中有一个is_active属性为False,ModelBackend和RemoteUserBackend认证后端禁止此类用户认证。如果一个自定义的用户模型没有is_acitve属性,则允许进行后端认证。

You can use AllowAllUsersModelBackend or
AllowAllUsersRemoteUserBackend if you want to allow inactive users to
authenticate.

你可以使用AllowAllUsersModelBackend或者AllowAllUsersRemoteUserBackend允许非激活用户进行认证。

The support for anonymous users in the permission system allows for a
scenario where anonymous users have permissions to do something while
inactive authenticated users do not.

在许可系统中针对匿名用户的支持方案,允许匿名用户进行某项操作的同时禁止非激活用户进行此项操作。

Do not forget to test for the is_active attribute of the user in your
own backend permission methods.

别忘了在你自己记得后端许可方法中对is_active属性进行测试。

Handling object permissions¶

处理对象许可

Django’s permission framework has a foundation for object permissions,
though there is no implementation for it in the core. That means that
checking for object permissions will always return False or an empty
list (depending on the check performed). An authentication backend
will receive the keyword parameters obj and user_obj for each object
related authorization method and can return the object level
permission as appropriate.

django许可框架是对象许可的基本框架,但是并没有在框架源代码中事项相应的许可。这就意味着如果用户检查对象的许可是,总是会返回False或者空列表。正确的方法是在认证后端进行定义,使用关键字对象obj或者user_obj,为每一个对象的许可进行定义。

Custom permissions¶

自定义许可

To create custom permissions for a given model object, use the
permissions model Meta attribute.

要针对某一个给定的模型对象创建一个自定义的许可,应该使用许可模型的Meta属性。

This example Task model creates three custom permissions, i.e.,
actions users can or cannot do with Task instances, specific to your
application:

下面的Task模型创建了三个用户自定义的许可:

class Task(models.Model):
    ...
    class Meta:
        permissions = (
            ("view_task", "Can see available tasks"),
            ("change_task_status", "Can change the status of tasks"),
            ("close_task", "Can remove a task by setting its status as closed"),
        )

The only thing this does is create those extra permissions when you
run manage.py migrate (the function that creates permissions is
connected to the post_migrate signal). Your code is in charge of
checking the value of these permissions when a user is trying to
access the functionality provided by the application (viewing tasks,
changing the status of tasks, closing tasks.) Continuing the above
example, the following checks if a user may view tasks:

上述例子中的自定义许可将在>>>python manage.py migrate后进行创建(由post_migrate信号所触发),你所编写的代码只需要对应用所提供的3个对应的许可字符串进行检查即可。下属例子用户检查用户的view tasks许可:

user.has_perm('app.view_task')

Extending the existing User model¶

拓展已有的用户模型

There are two ways to extend the default User model without
substituting your own model. If the changes you need are purely
behavioral, and don’t require any change to what is stored in the
database, you can create a proxy model based on User. This allows for
any of the features offered by proxy models including default
ordering, custom managers, or custom model methods.

除了替代已有的用户模型外,可以采用两种方式拓展django默认的User模型。如果你只想改变原有用户模型的行为,并不需要改变已经存储的用户数据,你可以创建一个代理模型,以扩充一些默认排序功能,自定义管理者或者自定义模型方法。

If you wish to store information related to User, you can use a
OneToOneField to a model containing the fields for additional
information. This one-to-one model is often called a profile model, as
it might store non-auth related information about a site user. For
example you might create an Employee model:

如果你想要存储一些与User模型有关的数据,你可以创建一个模型,并使用一对一属性OneToOneField来建立与User模型的关联,这个一对一的自定义模型通常称为profile model扩展模型。用于存储一些非认证的相关信息,以下的例子创建了一个自定义的员工模型,拓展了User模型:

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)

Assuming an existing Employee Fred Smith who has both a User and
Employee model, you can access the related information using Django’s
standard related model conventions:

如果已经存在了一个叫Fred Smith的员工,同时存在于User和Employee模型中,你可以利用对象关系方法轻松地获取到相关的信息:


>>> u = User.objects.get(username='fsmith')
>>> freds_department = u.employee.department

To add a profile model’s fields to the user page in the admin, define
an InlineModelAdmin (for this example, we’ll use a StackedInline) in
your app’s admin.py and add it to a UserAdmin class which is
registered with the User class:

如果要在django damin管理页中的用户页中增加用户自定义的拓展模型属性进行显示,需要在admin.py中定义一个InlineModelAdmin(例如StackedInline),并将其加入UserAdmin类进行注册。

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)

These profile models are not special in any way - they are just Django
models that happen to have a one-to-one link with a user model. As
such, they aren’t auto created when a user is created, but a
django.db.models.signals.post_save could be used to create or update
related models as appropriate.

这些拓展的模型并不是特殊的模型,他们也是django的模型,只是与user模型实现了一对一的联系。他们将不会在user创建的时候自动创建,但是可以利用django.db.models.signals.post_save的信号,来实现在user创建或更新的同时进行对应的拓展模型的创建或更新。

Using related models results in additional queries or joins to
retrieve the related data. Depending on your needs, a custom user
model that includes the related fields may be your better option,
however, existing relations to the default user model within your
project’s apps may justify the extra database load.

利用关系模型导致了需要增加相应的查询语句或者加入对关系数据的处理。根据你的需求,一个自定义个用户模型包括了一些关系型的拓展属性是一个很好的选择,但是同时,对应一个默认用户模型的项目应用需要检测相关的拓展数据是否进行了加载。

Substituting a custom User model¶

替代一个自定义的用户模型

Some kinds of projects may have authentication requirements for which
Django’s built-in User model is not always appropriate. For instance,
on some sites it makes more sense to use an email address as your
identification token instead of a username.

一些项目的认证需求可能超过了django内置的user模型所提供的功能。例如,一个网站需要使用email而不是用户名来区分用户。

Django allows you to override the default user model by providing a
value for the AUTH_USER_MODEL setting that references a custom model:

django允许你覆盖用户模型,覆盖的时候需要在settings.py中设置AUTH_USER_MODEL指向自定义的模型。

AUTH_USER_MODEL = ‘myapp.MyUser’ This dotted pair describes the name
of the Django app (which must be in your INSTALLED_APPS), and the name
of the Django model that you wish to use as your user model.

AUTH_USER_MODEL = ‘myapp.MyUser’,此处点号前是你所创建的django应用名称,点好后是你所创建的用户模型名。

Using a custom user model when starting a project¶

在项目开始时使用自定义的用户模型

If you’re starting a new project, it’s highly recommended to set up a
custom user model, even if the default User model is sufficient for
you. This model behaves identically to the default user model, but
you’ll be able to customize it in the future if the need arises:

如果你正在启动一个新项目的编写。即使django自带的用户模型足够使用,我们也还是建议你设置一个自定义的用户模型。这个自定义的模型等同于默认的用户模型,但是你可以在将来针对新的需求随时进行自定义和扩充。

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    pass

Don’t forget to point AUTH_USER_MODEL to it. Do this before creating
any migrations or running manage.py migrate for the first time.

别忘了,在settings.py中将AUTH_USER_MODEL指向上述自定义的user模型,然后使用>python manage.py migrate进行数据库的首次创建

Also, register the model in the app’s admin.py:

同时,别忘了在admin.py中注册上述自定义的模型。

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User

admin.site.register(User, UserAdmin)

Changing to a custom user model mid-project¶

在项目编写过程中改变自定义的用户模型。

Changing AUTH_USER_MODEL after you’ve created database tables is
significantly more difficult since it affects foreign keys and
many-to-many relationships, for example.

在你已经创建数据表后再改变AUTH_USER_MODEL是非常困难的,因为你将会受到已有数据表中外键、多对多关系的影响。

This change can’t be done automatically and requires manually fixing
your schema, moving your data from the old user table, and possibly
manually reapplying some migrations. See #25313 for an outline of the
steps.

这种改变无法进行自动执行,必须进行手工修复。一处原有用户数据表中的数据,可能还需要手工重新进行数据的迁移migration操作,可以查看#25313以了解进一步的说明。

Due to limitations of Django’s dynamic dependency feature for
swappable models, the model referenced by AUTH_USER_MODEL must be
created in the first migration of its app (usually called
0001_initial); otherwise, you’ll have dependency issues.

针对可交换数据模型的动态依赖的限制,AUTH_USER_MODEL所指向的数据模型必须在首次应用数据迁移migration是进行创建(一般是在该应用的0001_initial内),否则你就会遇到依赖的问题。

In addition, you may run into a CircularDependencyError when running
your migrations as Django won’t be able to automatically break the
dependency loop due to the dynamic dependency. If you see this error,
you should break the loop by moving the models depended on by your
user model into a second migration. (You can try making two normal
models that have a ForeignKey to each other and seeing how
makemigrations resolves that circular dependency if you want to see
how it’s usually done.)

另外,当你运行数据迁移时,django无法自动解除循环依赖,django你能会遇到一个循环依赖错误。如果你看到此类错误,你必须移除依赖于user用户模型的其他模型,并进行二次数据迁移操作。(你可以尝试创建两个普通的模型,并使用外键互相指向对方,看看makemigrations是如何解决循环依赖的。)

Reusable apps and AUTH_USER_MODEL¶

复用应用和AUTH_USER_MODEL

Reusable apps shouldn’t implement a custom user model. A project may
use many apps, and two reusable apps that implemented a custom user
model couldn’t be used together. If you need to store per user
information in your app, use a ForeignKey or OneToOneField to
settings.AUTH_USER_MODEL as described below.

如用应用不能实现一个自定义个用户模型。一个项目可能使用许许多多的应用,如果有两个可复用的应用实现了自定义用户模型的花,他们就不能同时使用。如果你需要在应用中存储每个用户的信息,使用一个外键或者一对一关系,指向AUTH_USER_MODEL。详见下述:

Referencing the User model¶

引用用户模型

If you reference User directly (for example, by referring to it in a
foreign key), your code will not work in projects where the
AUTH_USER_MODEL setting has been changed to a different user model.

当你的settings.py中AUTH_USER_MODEL已经指向了另一个用户模型后,如果你直接指向默认用户模型(例如,使用外键),你的代码将不能起作用。

get_user_model()[source]

Instead of referring to User directly, you should reference the user
model using django.contrib.auth.get_user_model(). This method will
return the currently active user model – the custom user model if one
is specified, or User otherwise.

你必须使用django.contrib.auth.get_user_model()指向用户模型,这种方法将会返回当前激活的用户模型,如果制定了自定义用户模型则返回之,否则就返回默认的用户模型。

When you define a foreign key or many-to-many relations to the user
model, you should specify the custom model using the AUTH_USER_MODEL
setting. For example:

当你定义一个外键或者多对多关系指向个用户模型,你必须利用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,
    )

When connecting to signals sent by the user model, you should specify
the custom model using the AUTH_USER_MODEL setting. For example:

当接收到一个来自user用户模型的信号后,你必须使用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)

Generally speaking, it’s easiest to refer to the user model with the
AUTH_USER_MODEL setting in code that’s executed at import time,
however, it’s also possible to call get_user_model() while Django is
importing models, so you could use models.ForeignKey(get_user_model(),
…).

If your app is tested with multiple user models, using
@override_settings(AUTH_USER_MODEL=…) for example, and you cache the
result of get_user_model() in a module-level variable, you may need to
listen to the setting_changed signal to clear the . For example:

通常来讲,最容易的指向自定义用户模型的方法是导入import时候指向AUTH_USER_MODEL。但是也可以使用get_user_model()来导入:models.ForeignKey(get_user_model(),…)
如果你的应用使用多个用户模型进行测试,例如使用@override_settings(AUTH_USER_MODELJ=…),那么,你在模块级变量中进行了get__user_model()结果的缓存,你必须监听setting的变化信号,并及时进行清理,例如:

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(**kwargs):
    if kwargs['setting'] == 'AUTH_USER_MODEL':
        apps.clear_cache()
        from myapp import some_module
        some_module.UserModel = get_user_model()

Changed in Django 1.11: The ability to call get_user_model() at import
time was added.

Django1.11的变化:在import时候可以使用get_uer_model()。

Specifying a custom user model¶

指定自定义的用户模型

Model design considerations

Think carefully before handling information not directly related to
authentication in your custom user model.

It may be better to store app-specific user information in a model
that has a relation with the user model. That allows each app to
specify its own user data requirements without risking conflicts with
other apps. On the other hand, queries to retrieve this related
information will involve a database join, which may have an effect on
performance. Django expects your custom user model to meet some
minimum requirements.

If you use the default authentication backend, then your model must
have a single unique field that can be used for identification
purposes. This can be a username, an email address, or any other
unique attribute. A non-unique username field is allowed if you use a
custom authentication backend that can support it.

The easiest way to construct a compliant custom user model is to
inherit from AbstractBaseUser. AbstractBaseUser provides the core
implementation of a user model, including hashed passwords and
tokenized password resets. You must then provide some key
implementation details:

模型设计时所必需的考虑的方面
在处理没有指向自定义用户模型的权限的数据时请仔细考虑。
最好在某个模型中存储与该应用特有的用户相关的信息,并将该模型指向系统的用户模型。这样的好处是允许每个应用都有自己特有的与系统用户模型向对应的特有数据而避免app之间的冲突。另一方面,对此类数据的查询需要使用数据库的join方法。django建议你自定义的用户模型遵守最小化原则。
如果你是用一个默认的认证后端,你的模型必须有一个唯一的属性(主键)。这个主键可以使用户名,邮件地址,或者其他为艺术性。如果你在使用一个自定义的认证后端,可以自行支持一个非唯一的用户名属性。

class models.CustomUser¶ USERNAME_FIELD¶ A string describing the name
of the field on the user model that is used as the unique identifier.
This will usually be a username of some kind, but it can also be an
email address, or any other unique identifier. The field must be
unique (i.e., have unique=True set in its definition), unless you use
a custom authentication backend that can support non-unique usernames.

class models.CustomUser
USERNAME_FIELD

一个字符串描述了用户名的属性,并作为用户模型的主键。当然也可以使用电子邮件或其他唯一属性。除非你自行定义认证后端以支持非唯一的用户名,此类属性必须是唯一的(例如,在定义时设置unique=True)。

In the following example, the field identifier is used as the
identifying field:

下述的例子,设置了主键唯一的属性:

class MyUser(AbstractBaseUser):
    identifier = models.CharField(max_length=40, unique=True)
    ...

    USERNAME_FIELD = 'identifier'

USERNAME_FIELD now supports ForeignKeys. Since there is no way to pass
model instances during the createsuperuser prompt, expect the user to
enter the value of to_field value (the primary_key by default) of an
existing instance.

USERNAME_FIELD现在支持外键。在创建超级用户的时候无法传递模型实例,需要用户输入一个已经存在的实例的to_field值(默认的主键)

EMAIL_FIELD¶ New in Django 1.11. A string describing the name of the
email field on the User model. This value is returned by
get_email_field_name().

EMAIL_FIELD

DJANGO1.11中新出现的属性,用户模型的属性,一个字符串,描述了email属性的值,可以使用get_email_field_name()获取

REQUIRED_FIELDS¶ A list of the field names that will be prompted for
when creating a user via the createsuperuser management command. The
user will be prompted to supply a value for each of these fields. It
must include any field for which blank is False or undefined and may
include additional fields you want prompted for when a user is created
interactively. REQUIRED_FIELDS has no effect in other parts of Django,
like creating a user in the admin.

REQUIRED_FIELDS

一个属性名的列表,用于在命令行下创建超级用户时进行提示。用户将在填充每一个属性值时收到提示。该属性必须包括全部非空的属性(blank=False)或者未定义的属性。当然,它也可以包括一些附加的属性,你可以在创建用户时进行交互地提示。REQUIRED_FIELDS 在qjango其他部分无效,例如在admin页面下创建用户。

For example, here is the partial definition for a user model that
defines two required fields - a date of birth and height:

例如:这里一个用户模型部分属性的定义,该模型定义了两个必须的属性,生日和高度(属性定义时,除非指定blank=True,否则默认为非空)

class MyUser(AbstractBaseUser):
    ...
    date_of_birth = models.DateField()
    height = models.FloatField()
    ...
    REQUIRED_FIELDS = ['date_of_birth', 'height']

Note

注意:

REQUIRED_FIELDS must contain all required fields on your user model,
but should not contain the USERNAME_FIELD or password as these fields
will always be prompted for. REQUIRED_FIELDS now supports ForeignKeys.
Since there is no way to pass model instances during the
createsuperuser prompt, expect the user to enter the value of to_field
value (the primary_key by default) of an existing instance.

REQUIRED_FIELDS 必须在用户模型中包含所有的请求的属性,但是不能包含USERNAME_FIELD或者password,因为这些属性即使不用REQUIRED_FIELDS也会提示。REQUIRED_FIELDS现在支持外键。因为目前创建超级用户是无法传递模型实例的,所以用户需要输入已知的实例的值赋值给to_field

is_active¶ A boolean attribute that indicates whether the user is
considered “active”. This attribute is provided as an attribute on
AbstractBaseUser defaulting to True. How you choose to implement it
will depend on the details of your chosen auth backends. See the
documentation of the is_active attribute on the built-in user model
for details.

is_active

一个布尔值属性,指明用户是否激活。这个属性有AbstractBaseUser定义,默认为True。如何去实现该属性的功能依据于你所选择的认证后端。查看内建用户模型中关于is_active属性的详细文档。

get_full_name()¶ Optional. A longer formal identifier for the user
such as their full name. If implemented, this appears alongside the
username in an object’s history in django.contrib.admin.

get_full_name()

可选。一个chang长人名用以区分用户。如果实现了该功能,则它将与username共存。

get_short_name()¶ Optional. A short, informal identifier for the user
such as their first name. If implemented, this replaces the username
in the greeting to the user in the header of django.contrib.admin.

get_short_name()

可选。一个短的,非正式的用户标示。比如用户的第一人名。如果实现了该功能,它将会在django.contrib.admin页面的上部的欢迎词中替换username

Changed in Django 2.0: In older versions, subclasses are required to
implement get_short_name() and get_full_name() as AbstractBaseUser has
implementations that raise NotImplementedError.

Django2.0的变化:在旧版中,资料,子类必须实现AbstrctBaseUser的get_short_name()和get_full_name()功能,否则会抛出NotImplementedError异常。

Importing AbstractBaseUser

AbstractBaseUser and BaseUserManager are importable from
django.contrib.auth.base_user so that they can be imported without
including django.contrib.auth in INSTALLED_APPS. The following
attributes and methods are available on any subclass of
AbstractBaseUser:

导入AbstractBaseUser
AbstractBaseUser和BaseUserManger可从django.contrib.auth.base_userr中导入,而不用在settings.py的INSTALLED_APPS中包含django.contrib.auth。可以从AbstractBaseUser的子类中获取下述属性和方法。

class models.AbstractBaseUser

class models.AbstractBaseUser

get_username()

get_username()

Returns the value of the field nominated by USERNAME_FIELD.

返回由USERNAME_FIELD指定的值

clean()

clean()

Normalizes the username by calling normalize_username(). If you override this method, be sure to call super() to retain the normalization.

用户名规范化,调用normalize_username()。如果你覆盖了该方法,要确保使用super()保留normalization。

classmethod get_email_field_name()

classmethod get_email_field_name()

New in Django 1.11. Returns the name of the email field specified by
the EMAIL_FIELD attribute. Defaults to ‘email’ if EMAIL_FIELD isn’t
specified.

django1.11中的新特性。返回email属性的值,由EMAIL_FIELD属性所指定。默认情况下,如果没有指定,则默认值为’email’

classmethod normalize_username(username)¶ Applies NFKC Unicode
normalization to usernames so that visually identical characters with
different Unicode code points are considered identical.

classmethod normalize_username(username)

应用NFKC Unicode编码规范化用户名。以使得同一个字符串的不同Unicode编码进行等效。

is_authenticated¶ Read-only attribute which is always True (as opposed
to AnonymousUser.is_authenticated which is always False). This is a
way to tell if the user has been authenticated. This does not imply
any permissions and doesn’t check if the user is active or has a valid
session. Even though normally you will check this attribute on
request.user to find out whether it has been populated by the
AuthenticationMiddleware (representing the currently logged-in user),
you should know this attribute is True for any User instance.

is_authenticated¶

只读属性。除了匿名用户AnonymousUser.is_authenticated为否外,其他情况下为True。这是获取用户已经被认证的有效途径。这并不意味着任何的许可,并不检查用户是否被激活或者拥有有效的session。即使你在用户请求的时候检查由AuthenticationMiddleware构成的这个属性(代表了当前登录用户),你必须知道,这个属性对任何用户实例来说都是True的。

is_anonymous¶ Read-only attribute which is always False. This is a way
of differentiating User and AnonymousUser objects. Generally, you
should prefer using is_authenticated to this attribute.

is_anonymous¶

只读属性,总是为False。可以用于区别用户和匿名用户对象。通常,优先使用is_authenticated属性。

set_password(raw_password)¶ Sets the user’s password to the given raw
string, taking care of the password hashing. Doesn’t save the
AbstractBaseUser object.

set_password(raw_password)¶

使用明文字符串给用户设置密码

When
the raw_password is None, the password will be set to an unusable
password, as if set_unusable_password() were used.

如果明文密码为None,则密码将会使用set_unusable_password()设成一个不可使用的密码,

check_password(raw_password)¶ Returns True if the given raw string is
the correct password for the user. (This takes care of the password
hashing in making the comparison.)

check_password(raw_password)¶

传入明文密码,如果对,则返回True(使用hash哈希值进行对比)

set_unusable_password()¶ Marks the user as having no password set.
This isn’t the same as having a blank string for a password.
check_password() for this user will never return True. Doesn’t save
the AbstractBaseUser object.

set_unusable_password()¶

标记用户没有密码。这并不代表用户使用空密码。如果使用check_password(),则不会反悔True。不会保存AbstractBaseUser对象

You may need this if authentication for your application takes place
against an existing external source such as an LDAP directory.

如果你拥有一个外部的用户源,例如LDAP目录,则你需要这样的一个认证方式。(确保LDAP里面的空密码用户能够被认证功能有效识别或拦截)

has_usable_password()¶ Returns False if set_unusable_password() has
been called for this user.

has_usable_password()¶

如果使用了set_unusable_password(),则此方法会返回False

get_session_auth_hash()¶ Returns an HMAC of the password field. Used
for Session invalidation on password change.

get_session_auth_hash()¶

返回一个password属性的哈希验证码。用于password改变后使原有的session失效。

AbstractUser subclasses AbstractBaseUser:

AbstractUser subclasses AbstractBaseUser:

class models.AbstractUser¶

class models.AbstractUser¶

clean()¶ New in Django 1.11. Normalizes the email by calling
BaseUserManager.normalize_email(). If you override this method, be
sure to call super() to retain the normalization.

clean()

django1.11新功能
规范化email,通过调用BaseUserManager.normalize_email()实现。如果你覆盖了此方法,要确保调用super()已保留规范化方法。

You should also define a custom manager for your user model. If your
user model defines username, email, is_staff, is_active, is_superuser,
last_login, and date_joined fields the same as Django’s default user,
you can just install Django’s UserManager; however, if your user model
defines different fields, you’ll need to define a custom manager that
extends BaseUserManager providing two additional methods:

你必须定义一个对自定义用户模型的自定义管理器。如果你的用户模型定义了与django默认用户模型相同的username,email,is_staff,is_active,is_superuser,last_login和date_joined属性,你可以直接安装django用户管理器,但是,如果你的用户模型定义了其他的属性,你将必须自行定义一个用户管理器,拓展BaseUserManger,以提供两个附加的方法:

class models.CustomUserManager¶

class models.CustomUserManager¶

create_user(username_field, password=None, **other_fields)¶ The
prototype of create_user() should accept the username field, plus all
required fields as arguments. For example, if your user model uses
email as the username field, and has date_of_birth as a required
field, then create_user should be defined as:

create_user(username_field, password=None, **other_fields)¶

create_user()的原型,必须接收用户名属性及其他必须的属性作为参数。例如,如果你的用户模型使用了email作为用户名属性,并且使用生日作为必须的属性,那么,create_user必须如下定义:

def create_user(self, email, date_of_birth, password=None):
    # create user 
    ...

create_superuser(username_field, password, **other_fields)¶ The
prototype of create_superuser() should accept the username field, plus
all required fields as arguments. For example, if your user model uses
email as the username field, and has date_of_birth as a required
field, then create_superuser should be defined as:

create_superuser(username_field, password, **other_fields)¶

create_superuser()原型,必须接收用户名属性及其他必须的属性作为参数.。例如,如果你的用户模型使用email作为用户名属性的值,并且生日作为必须的属性,那么创建超级用户的时候,必须如下定义:

def create_superuser(self, email, date_of_birth, password):
    # create superuser here
    ...

Unlike create_user(), create_superuser() must require the caller to provide a password.
不像create_user(),create_superuser()必须由调用者输入密码。

BaseUserManager provides the following utility methods:

BaseUserManager provides the following utility 提供了如下的实用方法:
class models.BaseUserManager¶

class models.BaseUserManager¶

classmethod normalize_email(email)¶ Normalizes email addresses by
lowercasing the domain portion of the email address.

classmethod normalize_email(email)¶

将email域名部分转为小写

get_by_natural_key(username)¶ Retrieves a user instance using the
contents of the field nominated by USERNAME_FIELD.

get_by_natural_key(username)¶

利用USERNAME_FIELD属性的值来获取用户实例

make_random_password(length=10, allowed_chars=’23456789’)¶

Returns a random password with the given length and given string of
allowed characters. Note that the default value of allowed_chars
doesn’t contain letters that can cause user confusion, including:

i, l, I, and 1 (lowercase letter i, lowercase letter L, uppercase
letter i, and the number one) o, O, and 0 (lowercase letter o,
uppercase letter o, and zero)

make_random_password(length=10, allowed_chars=23456789’)¶

对给定的长度和指定的字符范围参数返回随机密码。注意,默认的给定的字符值不能产生冲突,包括:
-i,l,I和1(小写的i,小写的L,大写的i,数字一)
-o,O,0(小写o,大写o,数字〇)

Extending Django’s default User¶

拓展django默认用户

If you’re entirely happy with Django’s User model and you just want to
add some additional profile information, you could simply subclass
django.contrib.auth.models.AbstractUser and add your custom profile
fields, although we’d recommend a separate model as described in the
“Model design considerations” note of Specifying a custom user model.
AbstractUser provides the full implementation of the default User as
an abstract model.

如果你对django的user用户模型满意,你只需要添加一些额外的拓展信息,你可以简单地对.contrib.auth.models.AbstractUser进行子类化,添加你自己定义的拓展属性。虽然我们建议使用一个分离式的模型(模型设计的考虑)用以区别自定义的用户模型。AbastractUser提供了默认用户得抽象模型的的完整的实现

Custom users and the built-in auth forms¶

自定义用户和内建权限表格

Django’s built-in forms and views make certain assumptions about the
user model that they are working with.

The following forms are compatible with any subclass of
AbstractBaseUser:

AuthenticationForm: Uses the username field specified by
USERNAME_FIELD. SetPasswordForm PasswordChangeForm
AdminPasswordChangeForm

django内建的表格和视图解决了用户模型运行中的一些需求。
下述表格适用于任何AbstractBaseUser的子类:
-AuthenticationForm:使用USERNAME_FIELD指定的用户名属性
-SetPasswordForm
-PasswordChangeForm
-AdminPasswordChangeForm

The following forms make assumptions about the user model and can be
used as-is if those assumptions are met:

下列forms表格可以再用户模型的相关需求时予以满足:

PasswordResetForm: Assumes that the user model has a field that stores
the user’s email address with the name returned by
get_email_field_name() (email by default) that can be used to identify
the user and a boolean field named is_active to prevent password
resets for inactive users. Finally, the following forms are tied to
User and need to be rewritten or extended to work with a custom user
model:

PasswordResetForm:嘉定用户模型有一个属性用于存储用户的email地址,并由get_email_field_name()(如不设置,则默返回email
UserCreationForm
UserChangeForm
If your custom user model is a simple subclass of AbstractUser, then you can extend these forms in this manner:

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',)

Custom users and django.contrib.admin

自定义用户和django.contrib.admin

If you want your custom user model to also work with the admin, your user model must define some additional attributes and methods. These methods allow the admin to control access of the user to admin content:

class models.CustomUser
is_staff¶
Returns True if the user is allowed to have access to the admin site.

is_active¶
Returns True if the user account is currently active.

has_perm(perm, obj=None):
Returns True if the user has the named permission. If obj is provided, the permission needs to be checked against a specific object instance.

has_module_perms(app_label):
Returns True if the user has permission to access models in the given app.

You will also need to register your custom user model with the admin. If your custom user model extends django.contrib.auth.models.AbstractUser, you can use Django’s existing django.contrib.auth.admin.UserAdmin class. However, if your user model extends AbstractBaseUser, you’ll need to define a custom ModelAdmin class. It may be possible to subclass the default django.contrib.auth.admin.UserAdmin; however, you’ll need to override any of the definitions that refer to fields on django.contrib.auth.models.AbstractUser that aren’t on your custom user class.

Custom users and permissions¶

自定义用户和许可

To make it easy to include Django’s permission framework into your own
user class, Django provides PermissionsMixin. This is an abstract
model you can include in the class hierarchy for your user model,
giving you all the methods and database fields necessary to support
Django’s permission model.

将django许可框架包含入你的用户类中,django提供了PernissionsMixin。这是一个抽象的模型,你可以包含着各类,继承它,给与你的用户模型所有的方法和数据库属性,满足django许可模型的需求。

PermissionsMixin provides the following methods and attributes:

PermissionsMixin提供了下述方法和属性:

class models.PermissionsMixin¶
is_superuser¶

Boolean. Designates that this user has all permissions without
explicitly assigning them.

布尔变量。指明用户在没有明确地分配权限时是否拥有所有的许可

get_group_permissions(obj=None)¶

Returns a set of permission strings that the user has, through their groups.

返回用户许可的字符串集合,这些许可通过用户所属的组进行获取

If obj is passed in, only returns the group permissions for this
specific object.

如果对象已经通过认证,则只返回该用户实例对象所属组的许可

get_all_permissions(obj=None)¶

Returns a set of permission strings that the user has, both through
group and user permissions.

If obj is passed in, only returns the permissions for this specific
object.

返回用户拥有的许可的字符串集合,同时从用户所属组及用户本身的权限中获取。
如果用户对象已经通过认证,则只返回调用该方法的对象的相关结果。

has_perm(perm, obj=None)¶

Returns True if the user has the specified permission, where perm is
in the format “.” (see permissions).
If the user is inactive, this method will always return False.

If obj is passed in, this method won’t check for a permission for
model, but for this specific object.

如果用户拥有指定的许可参数,则返回True,许可的格式是:“.”(查看许可)。
如果用户是非激活状态,则此方法总是返回False

has_perms(perm_list, obj=None)¶

Returns True if the user has each of the specified permissions, where
each perm is in the format “.”. If the
user is inactive, this method will always return False.

If obj is passed in, this method won’t check for permissions for the
model, but for the specific object.

如果用户拥有给定的许可列表,则返回True。每一个许可必须以“.”的形式进行给定。如果用户非激活,则返回False。

has_module_perms(package_name)¶

Returns True if the user has any permissions in the given package (the
Django app label). If the user is inactive, this method will always
return False.

返回针对某个给定的包(django应用标签)的许可,如果用户非激活,则返回False。

PermissionsMixin and ModelBackend

If you don’t include the PermissionsMixin, you must ensure you don’t
invoke the permissions methods on ModelBackend. ModelBackend assumes
that certain fields are available on your user model. If your user
model doesn’t provide those fields, you’ll receive database errors
when you check permissions.
如果你没有包含PermissionsMixin,你必须确保你在ModelBackend不会触发许可方法。ModelBackend假设了在你的用户面膜模型中某个属性是可以获得的。如果你的用户模型没有提供上述属性,你将在检查许可的时候接受到数据库错误。
Custom users and proxy models¶

自定义用户和代理模型

One limitation of custom user models is that installing a custom user
model will break any proxy model extending User. Proxy models must be
based on a concrete base class; by defining a custom user model, you
remove the ability of Django to reliably identify the base class.

If your project uses proxy models, you must either modify the proxy to
extend the user model that’s in use in your project, or merge your
proxy’s behavior into your User subclass.
自定义用户模型的一个限制是安装自定义的用户模型会打断任何拓展自user模型的代理模型。代理模型必须基于一个具体的基类,定义一个自定义的用户模型,你实际上将移除django可靠地鉴别积累的能力。
A full example¶

一个完整的例子

Here is an example of an admin-compliant custom user app. This user
model uses an email address as the username, and has a required date
of birth; it provides no permission checking, beyond a simple admin
flag on the user account. This model would be compatible with all the
built-in auth forms and views, except for the user creation forms.
This example illustrates how most of the components work together, but
is not intended to be copied directly into projects for production
use.

This code would all live in a models.py file for a custom
authentication app:

这里是一个依从于admin的自定义用户应用的例子。这里的用户模型使用了一个email地址作为用户名,而且将日期作为必须的字段。它利用简单地管理员标示来禁止一半用户的许可检查。这个模型将能够兼容所有内检的权限表格和视图,除了用户特有的表格外。这个例子阐述了多数组件一起工作的情况,但是并不建议你直接将其拷贝到你的项目中作为生产用途。
这里的代码存在于自定义模型所属APP的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):
        """
        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

Then, to register this custom user model with Django’s admin, the
following code would be required in the app’s admin.py file:

接着,在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 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 forms.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
    password hash display field.
    """
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = MyUser
        fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin')

    def clean_password(self):
        # Regardless of what the user provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]


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)

Finally, specify the custom model as the default user model for your
project using the AUTH_USER_MODEL setting in your settings.py:

最后,指定自定义模型作为默认的用户模型,在settings.py里面的AUTH_USER_MODEL字段中设置:

AUTH_USER_MODEL = 'customauth.MyUser'
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值