{"title":"Django 中的自定义验证","version":"4.1","locale":"zh-hans","docname":"topics/auth/customizing","url":"/zh-hans/4.1/topics/auth/customizing/","canonical":"https://djangodocs.dev/zh-hans/4.1/topics/auth/customizing/","summary":"Django 自带的身份验证已经足够满足大多数常见的情况，但你可能有一些需求没有被开箱即用的默认值所满足。","html":"<h1>Django 中的自定义验证<a class=\"heading-anchor\" href=\"#customizing-authentication-in-django\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django 自带的身份验证已经足够满足大多数常见的情况，但你可能有一些需求没有被开箱即用的默认值所满足。在你的项目中定制身份验证需要了解所提供系统的哪些点是可扩展或可替换的。本文档详细介绍了如何定制认证系统。</p>\n<p>当用户模型中存储的用户名和密码需要对一个不同于 Django 默认服务验证时，<a class=\"reference internal\" href=\"#authentication-backends\"><span class=\"std std-ref\">认证后端</span></a> 提供了一个可扩展的系统。</p>\n<p>你可以给你的模型 <a class=\"reference internal\" href=\"#custom-permissions\"><span class=\"std std-ref\">自定义权限</span></a> 并且可以通过 Django 的授权系统检查。</p>\n<p>你可以 <a class=\"reference internal\" href=\"#extending-user\"><span class=\"std std-ref\">扩展</span></a> 默认的 <code class=\"docutils literal notranslate\">User</code> 模型，或者完全自定义一个模型进行 <a class=\"reference internal\" href=\"#auth-custom-user\"><span class=\"std std-ref\">替换</span></a></p>\n<section id=\"other-authentication-sources\">\n<span id=\"authentication-backends\"></span><h2>其它认证资源<a class=\"heading-anchor\" href=\"#other-authentication-sources\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>有时候你需要连接到其他认证源——一个包含用户名及密码的源或者认证方法。</p>\n<p>例如，你的公司可能已经有了一个 LDAP 配置，为每个员工存储了一个用户名和密码。如果用户在 LDAP 和基于 Django 的应用程序中分别有不同的账户，那么对于网络管理员和用户本身来说都是一件很麻烦的事情。</p>\n<p>所以，为了处理这样的情况，Django 认证系统让你可以插入其他认证源。你可以覆盖 Django 默认的基于数据库的方案，也可以将默认系统与其他系统串联使用。</p>\n<p>参见 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#authentication-backends-reference\"><span class=\"std std-ref\">认证后端参考</span></a>，了解 Django 所包含的认证后端的信息。</p>\n<section id=\"specifying-authentication-backends\">\n<h3>指定认证后端<a class=\"heading-anchor\" href=\"#specifying-authentication-backends\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>在幕后，Django 维护了一个 “认证后端” 列表，用于检查认证。当有人调用 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.authenticate\" title=\"django.contrib.auth.authenticate\"><code class=\"xref py py-func docutils literal notranslate\">django.contrib.auth.authenticate()</code></a> ——就像 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#how-to-log-a-user-in\"><span class=\"std std-ref\">如何登录用户</span></a> 中描述的那样——Django 会尝试对所有的认证后端进行认证。如果第一个认证方法失败，Django 就尝试第二个，以此类推，直到所有后端都尝试过。</p>\n<p>要使用的认证后端列表在 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTHENTICATION_BACKENDS\"><code class=\"xref std std-setting docutils literal notranslate\">AUTHENTICATION_BACKENDS</code></a> 配置中指定。这应该是一个指向知道如何验证的 Python 类的 Python 路径名列表。这些类可以是 Python 路径上的任何地方。</p>\n<p>默认情况下，<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTHENTICATION_BACKENDS\"><code class=\"xref std std-setting docutils literal notranslate\">AUTHENTICATION_BACKENDS</code></a> 配置为：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"p\">[</span><span class=\"s1\">&#39;django.contrib.auth.backends.ModelBackend&#39;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>That's the basic authentication backend that checks the Django users database\nand queries the built-in permissions. It does not provide protection against\nbrute force attacks via any rate limiting mechanism. You may either implement\nyour own rate limiting mechanism in a custom auth backend, or use the\nmechanisms provided by most web servers.</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTHENTICATION_BACKENDS\"><code class=\"xref std std-setting docutils literal notranslate\">AUTHENTICATION_BACKENDS</code></a> 的顺序很重要，所以如果同一个用户名和密码在多个后端都有效，Django 会在第一个正向匹配时停止处理。</p>\n<p>如果一个后端抛出 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/exceptions/#django.core.exceptions.PermissionDenied\" title=\"django.core.exceptions.PermissionDenied\"><code class=\"xref py py-class docutils literal notranslate\">PermissionDenied</code></a> 异常，则验证流程立马终止，Django 不会继续检查其后的后端。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>Once a user has authenticated, Django stores which backend was used to\nauthenticate the user in the user's session, and reuses the same backend\nfor the duration of that session whenever access to the currently\nauthenticated user is needed. This effectively means that authentication\nsources are cached on a per-session basis, so if you change\n<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTHENTICATION_BACKENDS\"><code class=\"xref std std-setting docutils literal notranslate\">AUTHENTICATION_BACKENDS</code></a>, you'll need to clear out session data if\nyou need to force users to re-authenticate using different methods. A\nsimple way to do that is to execute <code class=\"docutils literal notranslate\">Session.objects.all().delete()</code>.</p>\n</aside>\n</section>\n<section id=\"writing-an-authentication-backend\">\n<h3>编写一个认证后端<a class=\"heading-anchor\" href=\"#writing-an-authentication-backend\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>认证后端是一个类，它实现了两个必要的方法：<code class=\"docutils literal notranslate\">get_user(user_id)</code> 和 <code class=\"docutils literal notranslate\">authenticate(request, **credentials)</code>，以及一组可选的与权限相关的 <a class=\"reference internal\" href=\"#authorization-methods\"><span class=\"std std-ref\">认证方法</span></a>。</p>\n<p><code class=\"docutils literal notranslate\">get_user</code> 方法接收一个 <code class=\"docutils literal notranslate\">user_id</code> ——可以是用户名、数据库 ID 或其他什么，但必须是用户对象的主键——然后返回一个用户对象或 <code class=\"docutils literal notranslate\">None</code>。</p>\n<p><code class=\"docutils literal notranslate\">authenticate</code> 方法采用 <code class=\"docutils literal notranslate\">request</code> 参数和证书作为关键字参数。大多数情况下，它看起来像这样：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.backends</span> <span class=\"kn\">import</span> BaseBackend\n\n<span class=\"k\">class</span> <span class=\"nc\">MyBackend</span><span class=\"p\">(</span>BaseBackend<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">authenticate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> request<span class=\"p\">,</span> username<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> password<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Check the username/password and return a user.</span>\n        <span class=\"o\">...</span>\n</code></pre></div>\n<p>但它也可以认证一个令牌，比如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.backends</span> <span class=\"kn\">import</span> BaseBackend\n\n<span class=\"k\">class</span> <span class=\"nc\">MyBackend</span><span class=\"p\">(</span>BaseBackend<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">authenticate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> request<span class=\"p\">,</span> token<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Check the token and return a user.</span>\n        <span class=\"o\">...</span>\n</code></pre></div>\n<p>无论哪种方式，<code class=\"docutils literal notranslate\">authenticate()</code> 应该检查它所得到的凭证，如果凭证有效，则返回一个与这些凭证相匹配的用户对象。如果无效，则应返回 <code class=\"docutils literal notranslate\">None</code>。</p>\n<p><code class=\"docutils literal notranslate\">request</code> 是一个 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\">HttpRequest</code></a>，如果没有提供给 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.authenticate\" title=\"django.contrib.auth.authenticate\"><code class=\"xref py py-func docutils literal notranslate\">authenticate()</code></a> （将其传递给后端），则可能是 <code class=\"docutils literal notranslate\">None</code>。</p>\n<p>Django admin 与 Django <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#user-objects\"><span class=\"std std-ref\">User 对象</span></a> 紧密耦合。处理这个问题的最好方法是为每个存在于后台的用户创建一个 Django <code class=\"docutils literal notranslate\">User</code> 对象（例如，在你的 LDAP 目录中，你的外部 SQL 数据库中，等等），你可以提前写一个脚本来完成这个任务，或者你的 <code class=\"docutils literal notranslate\">authenticate</code> 方法可以在用户第一次登录时完成。</p>\n<p>下面是一个后端实例，它可以根据 <code class=\"docutils literal notranslate\">settings.py</code> 文件中定义的用户名和密码变量进行验证，并在用户第一次验证时创建一个 Django <code class=\"docutils literal notranslate\">User</code> 对象：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.conf</span> <span class=\"kn\">import</span> settings\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.backends</span> <span class=\"kn\">import</span> BaseBackend\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.hashers</span> <span class=\"kn\">import</span> check_password\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.models</span> <span class=\"kn\">import</span> User\n\n<span class=\"k\">class</span> <span class=\"nc\">SettingsBackend</span><span class=\"p\">(</span>BaseBackend<span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.</span>\n\n<span class=\"sd\">    Use the login name and a hash of the password. For example:</span>\n\n<span class=\"sd\">    ADMIN_LOGIN = &#39;admin&#39;</span>\n<span class=\"sd\">    ADMIN_PASSWORD = &#39;pbkdf2_sha256$30000$Vo0VlMnkR4Bk$qEvtdyZRWTcOsCnI/oQ7fVOu1XAURIZYoOZ3iq8Dr4M=&#39;</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">authenticate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> request<span class=\"p\">,</span> username<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> password<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        login_valid <span class=\"o\">=</span> <span class=\"p\">(</span>settings<span class=\"o\">.</span>ADMIN_LOGIN <span class=\"o\">==</span> username<span class=\"p\">)</span>\n        pwd_valid <span class=\"o\">=</span> check_password<span class=\"p\">(</span>password<span class=\"p\">,</span> settings<span class=\"o\">.</span>ADMIN_PASSWORD<span class=\"p\">)</span>\n        <span class=\"k\">if</span> login_valid <span class=\"ow\">and</span> pwd_valid<span class=\"p\">:</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                user <span class=\"o\">=</span> User<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>username<span class=\"o\">=</span>username<span class=\"p\">)</span>\n            <span class=\"k\">except</span> User<span class=\"o\">.</span>DoesNotExist<span class=\"p\">:</span>\n                <span class=\"c1\"># Create a new user. There&#39;s no need to set a password</span>\n                <span class=\"c1\"># because only the password from settings.py is checked.</span>\n                user <span class=\"o\">=</span> User<span class=\"p\">(</span>username<span class=\"o\">=</span>username<span class=\"p\">)</span>\n                user<span class=\"o\">.</span>is_staff <span class=\"o\">=</span> <span class=\"kc\">True</span>\n                user<span class=\"o\">.</span>is_superuser <span class=\"o\">=</span> <span class=\"kc\">True</span>\n                user<span class=\"o\">.</span>save<span class=\"p\">()</span>\n            <span class=\"k\">return</span> user\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">get_user</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> user_id<span class=\"p\">):</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> User<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>pk<span class=\"o\">=</span>user_id<span class=\"p\">)</span>\n        <span class=\"k\">except</span> User<span class=\"o\">.</span>DoesNotExist<span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"kc\">None</span>\n</code></pre></div>\n</section>\n<section id=\"handling-authorization-in-custom-backends\">\n<span id=\"authorization-methods\"></span><h3>在自定义后端处理认证<a class=\"heading-anchor\" href=\"#handling-authorization-in-custom-backends\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>自定义的认证后端可以提供他们自己的权限。</p>\n<p>用户模型和它的管理器会把权限查找函数（<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.get_user_permissions\" title=\"django.contrib.auth.models.User.get_user_permissions\"><code class=\"xref py py-meth docutils literal notranslate\">get_user_permissions()</code></a>、<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.get_group_permissions\" title=\"django.contrib.auth.models.User.get_group_permissions\"><code class=\"xref py py-meth docutils literal notranslate\">get_group_permissions()</code></a>、<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.get_all_permissions\" title=\"django.contrib.auth.models.User.get_all_permissions\"><code class=\"xref py py-meth docutils literal notranslate\">get_all_permissions()</code></a>、<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.has_perm\" title=\"django.contrib.auth.models.User.has_perm\"><code class=\"xref py py-meth docutils literal notranslate\">has_perm()</code></a>、<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.has_module_perms\" title=\"django.contrib.auth.models.User.has_module_perms\"><code class=\"xref py py-meth docutils literal notranslate\">has_module_perms()</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.UserManager.with_perm\" title=\"django.contrib.auth.models.UserManager.with_perm\"><code class=\"xref py py-meth docutils literal notranslate\">with_perm()</code></a>）委托给任何实现了这些函数的认证后端。</p>\n<p>用户所拥有的权限将是所有验证后端返回的所有权限的一个超集。也就是说，如果任何后端之一将一个权限赋予了用户，那么 Django 最终也将该权限赋予这个用户。</p>\n<p>如果后端在 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.has_perm\" title=\"django.contrib.auth.models.User.has_perm\"><code class=\"xref py py-meth docutils literal notranslate\">has_perm()</code></a> 或 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.has_module_perms\" title=\"django.contrib.auth.models.User.has_module_perms\"><code class=\"xref py py-meth docutils literal notranslate\">has_module_perms()</code></a> 中引发 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/exceptions/#django.core.exceptions.PermissionDenied\" title=\"django.core.exceptions.PermissionDenied\"><code class=\"xref py py-class docutils literal notranslate\">PermissionDenied</code></a> 异常，认证就会立即失败，Django 也不会检查后面的后端。</p>\n<p>后端可以像这样为管理员实现权限：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.backends</span> <span class=\"kn\">import</span> BaseBackend\n\n<span class=\"k\">class</span> <span class=\"nc\">MagicAdminBackend</span><span class=\"p\">(</span>BaseBackend<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">has_perm</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> user_obj<span class=\"p\">,</span> perm<span class=\"p\">,</span> obj<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> user_obj<span class=\"o\">.</span>username <span class=\"o\">==</span> settings<span class=\"o\">.</span>ADMIN_LOGIN\n</code></pre></div>\n<p>这就给了上例中授予访问权限的用户全部权限。请注意，除了给相关的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">django.contrib.auth.models.User</code></a> 函数提供相同的参数外，后台的认证函数都以用户对象（可能是一个匿名用户）作为参数。</p>\n<p>一个完整的鉴权实现可以在 <a class=\"extlink-source reference external\" href=\"https://github.com/django/django/blob/stable/4.1.x/django/contrib/auth/backends.py\">django/contrib/auth/backends.py</a> 的 <code class=\"docutils literal notranslate\">ModelBackend</code> 里找到，这是默认的后端，并且在大多数时候会查询 <code class=\"docutils literal notranslate\">auth_permission</code> 表。</p>\n<section id=\"authorization-for-anonymous-users\">\n<span id=\"anonymous-auth\"></span><h4>匿名用户的授权<a class=\"heading-anchor\" href=\"#authorization-for-anonymous-users\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>匿名用户是指那些没有验证过的用户，也就是说，他们没有提供任何有效的验证信息。然而，这并不一定意味着他们就无权做任何事。在最基本的层面上，大多数站点允许匿名用户浏览大部分页面，而且很多站点也允许匿名评论。</p>\n<p>Django's permission framework does not have a place to store permissions for\nanonymous users. However, the user object passed to an authentication backend\nmay be an <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.AnonymousUser\" title=\"django.contrib.auth.models.AnonymousUser\"><code class=\"xref py py-class docutils literal notranslate\">django.contrib.auth.models.AnonymousUser</code></a> object, allowing\nthe backend to specify custom authorization behavior for anonymous users. This\nis especially useful for the authors of reusable apps, who can delegate all\nquestions of authorization to the auth backend, rather than needing settings,\nfor example, to control anonymous access.</p>\n</section>\n<section id=\"authorization-for-inactive-users\">\n<span id=\"inactive-auth\"></span><h4>非激活用户认证<a class=\"heading-anchor\" href=\"#authorization-for-inactive-users\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>非激活用户是指 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.is_active\" title=\"django.contrib.auth.models.User.is_active\"><code class=\"xref py py-attr docutils literal notranslate\">is_active</code></a> 字段设置为 <code class=\"docutils literal notranslate\">False</code> 的用户。<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.backends.ModelBackend\" title=\"django.contrib.auth.backends.ModelBackend\"><code class=\"xref py py-class docutils literal notranslate\">ModelBackend</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend\" title=\"django.contrib.auth.backends.RemoteUserBackend\"><code class=\"xref py py-class docutils literal notranslate\">RemoteUserBackend</code></a> 认证后端禁止这些用户进行认证。如果一个自定义用户模型没有 <a class=\"reference internal\" href=\"#django.contrib.auth.models.CustomUser.is_active\" title=\"django.contrib.auth.models.CustomUser.is_active\"><code class=\"xref py py-attr docutils literal notranslate\">is_active</code></a> 字段，那么所有用户都将被允许认证。</p>\n<p>如果你想让非激活用户进行身份认证，可以使用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.backends.AllowAllUsersModelBackend\" title=\"django.contrib.auth.backends.AllowAllUsersModelBackend\"><code class=\"xref py py-class docutils literal notranslate\">AllowAllUsersModelBackend</code></a> 或 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.backends.AllowAllUsersRemoteUserBackend\" title=\"django.contrib.auth.backends.AllowAllUsersRemoteUserBackend\"><code class=\"xref py py-class docutils literal notranslate\">AllowAllUsersRemoteUserBackend</code></a>。</p>\n<p>权限系统中对匿名用户的支持，可以实现匿名用户有权限做某事，而非激活的认证用户没有权限的场景。</p>\n<p>不要忘记在自己的后端权限方法中测试用户的 <code class=\"docutils literal notranslate\">is_active</code> 属性。</p>\n</section>\n<section id=\"handling-object-permissions\">\n<h4>处理对象权限<a class=\"heading-anchor\" href=\"#handling-object-permissions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Django 的权限框架有一个对象权限的基础，尽管在核心中没有实现。这意味着对对象权限的检查总是返回 <code class=\"docutils literal notranslate\">False</code> 或一个空列表（取决于所执行的检查）。认证后端将为每个与对象相关的授权方法接收关键字参数 <code class=\"docutils literal notranslate\">obj</code> 和 <code class=\"docutils literal notranslate\">user_obj</code>，并可以适当返回对象级别的权限。</p>\n</section>\n</section>\n</section>\n<section id=\"custom-permissions\">\n<span id=\"id1\"></span><h2>自定义权限<a class=\"heading-anchor\" href=\"#custom-permissions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>要为给定的模型对象创建自定义权限，使用 <code class=\"docutils literal notranslate\">permissions</code> <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/db/models/#meta-options\"><span class=\"std std-ref\">模型 Meta 属性</span></a>。</p>\n<p>这个 <code class=\"docutils literal notranslate\">Task</code> 模型创建了两个自定义权限，即用户可以或不可以对 <code class=\"docutils literal notranslate\">Task</code> 实例进行的操作，具体到你的应用程序：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">Task</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        permissions <span class=\"o\">=</span> <span class=\"p\">[</span>\n            <span class=\"p\">(</span><span class=\"s2\">&quot;change_task_status&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Can change the status of tasks&quot;</span><span class=\"p\">),</span>\n            <span class=\"p\">(</span><span class=\"s2\">&quot;close_task&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Can remove a task by setting its status as closed&quot;</span><span class=\"p\">),</span>\n        <span class=\"p\">]</span>\n</code></pre></div>\n<p>这样做的唯一作用就是当你运行 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/django-admin/#django-admin-migrate\"><code class=\"xref std std-djadmin docutils literal notranslate\">manage.py migrate</code></a> 时，创建这些额外的权限（创建权限的函数连接到 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/signals/#django.db.models.signals.post_migrate\" title=\"django.db.models.signals.post_migrate\"><code class=\"xref py py-data docutils literal notranslate\">post_migrate</code></a> 信号）。你的代码负责在用户试图访问应用程序提供的功能（改变任务状态或关闭任务）时检查这些权限的值。 继续上面的例子，下面检查用户是否可以关闭任务：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>user<span class=\"o\">.</span>has_perm<span class=\"p\">(</span><span class=\"s1\">&#39;app.close_task&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"extending-the-existing-user-model\">\n<span id=\"extending-user\"></span><h2>扩展现有的 <code class=\"docutils literal notranslate\">User</code> 模型<a class=\"heading-anchor\" href=\"#extending-the-existing-user-model\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>有两种方法可以扩展默认的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a> 模型，而不用替换自己的模型。如果你需要的是纯粹的行为改变，而不需要改变数据库中存储的内容，你可以基于 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a> 创建一个 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/db/models/#proxy-models\"><span class=\"std std-ref\">代理模型</span></a>。这允许代理模型提供的任何功能，包括默认排序、自定义管理器或自定义模型方法。</p>\n<p>如果你希望存储与 <code class=\"docutils literal notranslate\">User</code> 相关的信息，你可以使用一个 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/fields/#django.db.models.OneToOneField\" title=\"django.db.models.OneToOneField\"><code class=\"xref py py-class docutils literal notranslate\">OneToOneField</code></a> 到一个包含字段的模型，以获得额外的信息。这种一对一的模型通常被称为 profile 模型，因为它可能会存储一个站点用户的非认证相关信息。例如，你可以创建一个 Employee 模型：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.models</span> <span class=\"kn\">import</span> User\n\n<span class=\"k\">class</span> <span class=\"nc\">Employee</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    user <span class=\"o\">=</span> models<span class=\"o\">.</span>OneToOneField<span class=\"p\">(</span>User<span class=\"p\">,</span> on_delete<span class=\"o\">=</span>models<span class=\"o\">.</span>CASCADE<span class=\"p\">)</span>\n    department <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>假设现有的雇员 Fred Smith 同时拥有 User 和 Employee 模型，可以使用 Django 的标准关联模型约束来访问相关信息：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>u <span class=\"o\">=</span> User<span class=\"o\">.</span>objects<span class=\"o\">.</span>get<span class=\"p\">(</span>username<span class=\"o\">=</span><span class=\"s1\">&#39;fsmith&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>freds_department <span class=\"o\">=</span> u<span class=\"o\">.</span>employee<span class=\"o\">.</span>department\n</code></pre></div>\n<p>要将配置文件模型的字段添加到管理员的用户页面中，在你的应用程序的 <code class=\"docutils literal notranslate\">admin.py</code> 中定义一个 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin\" title=\"django.contrib.admin.InlineModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\">InlineModelAdmin</code></a> （在这个例子中，我们将使用一个 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.StackedInline\" title=\"django.contrib.admin.StackedInline\"><code class=\"xref py py-class docutils literal notranslate\">StackedInline</code></a>），并将其添加到一个 <code class=\"docutils literal notranslate\">UserAdmin</code> 类中，该类用 <code class=\"xref py py-class docutils literal notranslate\">User`</code> 类注册：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib</span> <span class=\"kn\">import</span> admin\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.admin</span> <span class=\"kn\">import</span> UserAdmin <span class=\"k\">as</span> BaseUserAdmin\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.models</span> <span class=\"kn\">import</span> User\n\n<span class=\"kn\">from</span> <span class=\"nn\">my_user_profile_app.models</span> <span class=\"kn\">import</span> Employee\n\n<span class=\"c1\"># Define an inline admin descriptor for Employee model</span>\n<span class=\"c1\"># which acts a bit like a singleton</span>\n<span class=\"k\">class</span> <span class=\"nc\">EmployeeInline</span><span class=\"p\">(</span>admin<span class=\"o\">.</span>StackedInline<span class=\"p\">):</span>\n    model <span class=\"o\">=</span> Employee\n    can_delete <span class=\"o\">=</span> <span class=\"kc\">False</span>\n    verbose_name_plural <span class=\"o\">=</span> <span class=\"s1\">&#39;employee&#39;</span>\n\n<span class=\"c1\"># Define a new User admin</span>\n<span class=\"k\">class</span> <span class=\"nc\">UserAdmin</span><span class=\"p\">(</span>BaseUserAdmin<span class=\"p\">):</span>\n    inlines <span class=\"o\">=</span> <span class=\"p\">(</span>EmployeeInline<span class=\"p\">,)</span>\n\n<span class=\"c1\"># Re-register UserAdmin</span>\nadmin<span class=\"o\">.</span>site<span class=\"o\">.</span>unregister<span class=\"p\">(</span>User<span class=\"p\">)</span>\nadmin<span class=\"o\">.</span>site<span class=\"o\">.</span>register<span class=\"p\">(</span>User<span class=\"p\">,</span> UserAdmin<span class=\"p\">)</span>\n</code></pre></div>\n<p>这些 profile 模型并没有任何特殊之处——它们只是 Django 模型，恰好与用户模型有一对一的联系。因此，当用户被创建时，它们并不会自动创建，但可以用一个 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/signals/#django.db.models.signals.post_save\" title=\"django.db.models.signals.post_save\"><code class=\"xref py py-attr docutils literal notranslate\">django.db.models.signals.post_save</code></a> 来适当地创建或更新相关模型。</p>\n<p>使用相关模型会导致额外的查询或连接来检索相关数据。根据你的需求，包含相关字段的自定义用户模型可能是你更好的选择，然而，在你的项目应用程序中与默认用户模型的现有关系可能会证明额外的数据库负载是合理的。</p>\n</section>\n<section id=\"substituting-a-custom-user-model\">\n<span id=\"auth-custom-user\"></span><h2>替换一个自定义的 <code class=\"docutils literal notranslate\">User</code> 模型。<a class=\"heading-anchor\" href=\"#substituting-a-custom-user-model\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>有些项目可能会有认证需求，而 Django 内置的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a> 模型并不总是合适。例如，在一些网站上，使用电子邮件地址作为你的身份识别标记比使用用户名更有意义。</p>\n<p>Django 允许你通过为 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\">AUTH_USER_MODEL</code></a> 配置提供一个引用自定义模型的值来覆盖默认的用户模型：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>AUTH_USER_MODEL <span class=\"o\">=</span> <span class=\"s1\">&#39;myapp.MyUser&#39;</span>\n</code></pre></div>\n<p>This dotted pair describes the <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/applications/#django.apps.AppConfig.label\" title=\"django.apps.AppConfig.label\"><code class=\"xref py py-attr docutils literal notranslate\">label</code></a> of the\nDjango app (which must be in your <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\">INSTALLED_APPS</code></a>), and the name of\nthe Django model that you wish to use as your user model.</p>\n<section id=\"using-a-custom-user-model-when-starting-a-project\">\n<h3>启动项目时使用自定义用户模型<a class=\"heading-anchor\" href=\"#using-a-custom-user-model-when-starting-a-project\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你准备启动一个新的项目，强烈推荐你设置一个自定义的用户模型，即使默认的用户模型对你来说已经足够了。这个模型的行为与默认用户模型相通，但是你能在未来需要的时候自定义它：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.models</span> <span class=\"kn\">import</span> AbstractUser\n\n<span class=\"k\">class</span> <span class=\"nc\">User</span><span class=\"p\">(</span>AbstractUser<span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n</code></pre></div>\n<p>不要忘记将 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\">AUTH_USER_MODEL</code></a> 指向它。在创建任何迁移或者首次运行 <code class=\"docutils literal notranslate\">manage.py migrate</code> 之前执行这个操作。</p>\n<p>同样的，在 app 中的 <code class=\"docutils literal notranslate\">admin.py</code> 中注册模型。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib</span> <span class=\"kn\">import</span> admin\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.admin</span> <span class=\"kn\">import</span> UserAdmin\n<span class=\"kn\">from</span> <span class=\"nn\">.models</span> <span class=\"kn\">import</span> User\n\nadmin<span class=\"o\">.</span>site<span class=\"o\">.</span>register<span class=\"p\">(</span>User<span class=\"p\">,</span> UserAdmin<span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"changing-to-a-custom-user-model-mid-project\">\n<h3>在项目中更改为自定义用户模型。<a class=\"heading-anchor\" href=\"#changing-to-a-custom-user-model-mid-project\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>在你已经建立数据库表之后再去修改 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\">AUTH_USER_MODEL</code></a> 要困难的多，因为它会影响外键和多对多关系。</p>\n<p>这个改动并不能自动完成，需要手动修复你的架构，将数据从旧的用户表移出，并有可能需要手动执行一些迁移操作。查看步骤概述，请查看 <a class=\"extlink-ticket reference external\" href=\"https://code.djangoproject.com/ticket/25313\">#25313</a>。</p>\n<p>由于 Django 对可交换模型的动态依赖特性的限制，<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\">AUTH_USER_MODEL</code></a> 所引用的模型必须在其应用的第一次迁移中创建（通常称为 <code class=\"docutils literal notranslate\">0001_initial</code>）；否则，你会出现依赖问题。</p>\n<p>此外，当你运行迁移时，你可能会遇到一个 <code class=\"docutils literal notranslate\">CircularDependencyError</code>，因为 Django 不会因为动态依赖而自动打破依赖循环。如果你看到这个错误，你应该通过将你的用户模型所依赖的模型移动到第二个迁移中来打破这个循环。（如果你想看看通常是怎么做的，你可以尝试做两个正常的模型，它们之间有一个 <code class=\"docutils literal notranslate\">ForeignKey</code>，看看 <code class=\"docutils literal notranslate\">makemigrations</code> 是如何解决这个循环依赖的。）</p>\n</section>\n<section id=\"reusable-apps-and-auth-user-model\">\n<h3>可重用应用和 <code class=\"docutils literal notranslate\">AUTH_USER_MODEL</code><a class=\"heading-anchor\" href=\"#reusable-apps-and-auth-user-model\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>可重用应用不应该实现自定义用户模型。一个项目可能会使用很多应用，两个实现了自定义用户模型的可重用应用不能一起使用。如果你需要在你的应用中存储每个用户的信息，可以使用一个 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/fields/#django.db.models.ForeignKey\" title=\"django.db.models.ForeignKey\"><code class=\"xref py py-class docutils literal notranslate\">ForeignKey</code></a> 或 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/fields/#django.db.models.OneToOneField\" title=\"django.db.models.OneToOneField\"><code class=\"xref py py-class docutils literal notranslate\">OneToOneField</code></a> 到 settings.AUTH_USER_MODEL，如下所述。</p>\n</section>\n<section id=\"referencing-the-user-model\">\n<h3>引用 <code class=\"docutils literal notranslate\">User</code> 模型<a class=\"heading-anchor\" href=\"#referencing-the-user-model\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你直接引用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a> （例如，通过在一个外键中引用它），你的代码将无法在 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\">AUTH_USER_MODEL</code></a> 配置已被更改为不同用户模型的项目中工作。</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.get_user_model\">\n<span class=\"sig-name descname\">get_user_model</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.get_user_model\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>与其直接引用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a>，不如使用 <code class=\"docutils literal notranslate\">django.contrib.auth.get_user_model()</code> 引用用户模型。这个方法将返回当前活动的用户模型——如果指定了自定义用户模型，则返回自定义用户模型，否则返回 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a>。</p>\n<p>在定义用户模型的外键或多对多关系时，应使用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\">AUTH_USER_MODEL</code></a> 配置指定自定义模型。例如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.conf</span> <span class=\"kn\">import</span> settings\n<span class=\"kn\">from</span> <span class=\"nn\">django.db</span> <span class=\"kn\">import</span> models\n\n<span class=\"k\">class</span> <span class=\"nc\">Article</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    author <span class=\"o\">=</span> models<span class=\"o\">.</span>ForeignKey<span class=\"p\">(</span>\n        settings<span class=\"o\">.</span>AUTH_USER_MODEL<span class=\"p\">,</span>\n        on_delete<span class=\"o\">=</span>models<span class=\"o\">.</span>CASCADE<span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n</code></pre></div>\n<p>连接用户模型发送的信号时，应使用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\">AUTH_USER_MODEL</code></a> 配置指定自定义模型。例如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.conf</span> <span class=\"kn\">import</span> settings\n<span class=\"kn\">from</span> <span class=\"nn\">django.db.models.signals</span> <span class=\"kn\">import</span> post_save\n\n<span class=\"k\">def</span> <span class=\"nf\">post_save_receiver</span><span class=\"p\">(</span>sender<span class=\"p\">,</span> instance<span class=\"p\">,</span> created<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n\npost_save<span class=\"o\">.</span>connect<span class=\"p\">(</span>post_save_receiver<span class=\"p\">,</span> sender<span class=\"o\">=</span>settings<span class=\"o\">.</span>AUTH_USER_MODEL<span class=\"p\">)</span>\n</code></pre></div>\n<p>一般来说，在导入时执行的代码中，用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\">AUTH_USER_MODEL</code></a> 配置来引用用户模型是最简单的，不过，也可以在 Django 导入模型时调用 <code class=\"docutils literal notranslate\">get_user_model()</code>，所以可以使用 <code class=\"docutils literal notranslate\">models.ForeignKey(get_user_model()，...)</code>。</p>\n<p>例如，如果你的应用是用多个用户模型进行测试的，使用 <code class=\"docutils literal notranslate\">&#64;override_settings(AUTH_USER_MODEL=...)</code>，并且你把 <code class=\"docutils literal notranslate\">get_user_model()</code> 的结果缓存在模块级变量中，你可能需要监听 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/signals/#django.test.signals.setting_changed\" title=\"django.test.signals.setting_changed\"><code class=\"xref py py-data docutils literal notranslate\">setting_changed</code></a> 信号来清除缓存。例如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.apps</span> <span class=\"kn\">import</span> apps\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth</span> <span class=\"kn\">import</span> get_user_model\n<span class=\"kn\">from</span> <span class=\"nn\">django.core.signals</span> <span class=\"kn\">import</span> setting_changed\n<span class=\"kn\">from</span> <span class=\"nn\">django.dispatch</span> <span class=\"kn\">import</span> receiver\n\n<span class=\"nd\">@receiver</span><span class=\"p\">(</span>setting_changed<span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">user_model_swapped</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"p\">,</span> setting<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n    <span class=\"k\">if</span> setting <span class=\"o\">==</span> <span class=\"s1\">&#39;AUTH_USER_MODEL&#39;</span><span class=\"p\">:</span>\n        apps<span class=\"o\">.</span>clear_cache<span class=\"p\">()</span>\n        <span class=\"kn\">from</span> <span class=\"nn\">myapp</span> <span class=\"kn\">import</span> some_module\n        some_module<span class=\"o\">.</span>UserModel <span class=\"o\">=</span> get_user_model<span class=\"p\">()</span>\n</code></pre></div>\n</dd></dl>\n\n</section>\n<section id=\"specifying-a-custom-user-model\">\n<span id=\"specifying-custom-user-model\"></span><h3>指定自定义用户模型<a class=\"heading-anchor\" href=\"#specifying-a-custom-user-model\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当你用自定义用户模型开始你的项目时，请停下来考虑一下这是否是你项目的正确选择。</p>\n<p>将所有用户相关信息保存在一个模型中，就不需要额外的或更复杂的数据库查询来检索相关模型。另一方面，在一个与你的自定义用户模型有关系的模型中存储特定应用的用户信息可能更合适。这允许每个应用程序指定自己的用户数据需求，而不会有潜在的冲突或破坏其他应用程序的假设。这也意味着，你会让你的用户模型尽可能的简单，专注于认证，并遵循 Django 期望自定义用户模型满足的最低要求。</p>\n<p>如果你使用默认的认证后端，那么你的模型必须有一个可用于识别目的的唯一字段。这可以是一个用户名，一个电子邮件地址，或任何其他独特的属性。如果你使用可以支持的自定义认证后端，则允许使用非唯一的用户名字段。</p>\n<p>最简单的方法是继承 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser\" title=\"django.contrib.auth.models.AbstractBaseUser\"><code class=\"xref py py-class docutils literal notranslate\">AbstractBaseUser</code></a>。 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser\" title=\"django.contrib.auth.models.AbstractBaseUser\"><code class=\"xref py py-class docutils literal notranslate\">AbstractBaseUser</code></a> 提供了用户模型的核心实现，包括哈希密码和令牌化密码重置。然后你必须提供一些关键的实现细节。</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.CustomUser\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">models.</span><span class=\"sig-name descname\">CustomUser</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.CustomUser\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.CustomUser.USERNAME_FIELD\">\n<span class=\"sig-name descname\">USERNAME_FIELD</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.CustomUser.USERNAME_FIELD\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>A string describing the name of the field on the user model that is\nused as the unique identifier. This will usually be a username of some\nkind, but it can also be an email address, or any other unique\nidentifier. The field <em>must</em> be unique (e.g. have <code class=\"docutils literal notranslate\">unique=True</code> set\nin its definition), unless you use a custom authentication backend that\ncan support non-unique usernames.</p>\n<p>接下来的样例中，<code class=\"docutils literal notranslate\">identifier</code> 字段将被用作识别字段：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">MyUser</span><span class=\"p\">(</span>AbstractBaseUser<span class=\"p\">):</span>\n    identifier <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">40</span><span class=\"p\">,</span> unique<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n    <span class=\"o\">...</span>\n    USERNAME_FIELD <span class=\"o\">=</span> <span class=\"s1\">&#39;identifier&#39;</span>\n</code></pre></div>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.CustomUser.EMAIL_FIELD\">\n<span class=\"sig-name descname\">EMAIL_FIELD</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.CustomUser.EMAIL_FIELD\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>用来描述用户模型中的邮件字段，该值通过 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser.get_email_field_name\" title=\"django.contrib.auth.models.AbstractBaseUser.get_email_field_name\"><code class=\"xref py py-meth docutils literal notranslate\">get_email_field_name()</code></a> 返回。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.CustomUser.REQUIRED_FIELDS\">\n<span class=\"sig-name descname\">REQUIRED_FIELDS</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.CustomUser.REQUIRED_FIELDS\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>在通过 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/django-admin/#django-admin-createsuperuser\"><code class=\"xref std std-djadmin docutils literal notranslate\">createsuperuser</code></a> 管理命令创建用户时，将提示用户输入的字段名称列表。用户将被提示为每个字段提供一个值。它必须包括 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/fields/#django.db.models.Field.blank\" title=\"django.db.models.Field.blank\"><code class=\"xref py py-attr docutils literal notranslate\">blank</code></a> 为 <code class=\"docutils literal notranslate\">False</code> 或未定义的任何字段，并可能包括你希望在交互式创建用户时提示的其他字段。<code class=\"docutils literal notranslate\">REQUIRED_FIELDS</code> 在 Django 的其他部分没有效果，比如在管理中创建用户。</p>\n<p>例如，这里是一个用户模型的部分定义，它定义了两个必填字段——出生日期和身高：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span> <span class=\"nc\">MyUser</span><span class=\"p\">(</span>AbstractBaseUser<span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n    date_of_birth <span class=\"o\">=</span> models<span class=\"o\">.</span>DateField<span class=\"p\">()</span>\n    height <span class=\"o\">=</span> models<span class=\"o\">.</span>FloatField<span class=\"p\">()</span>\n    <span class=\"o\">...</span>\n    REQUIRED_FIELDS <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;date_of_birth&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;height&#39;</span><span class=\"p\">]</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p><code class=\"docutils literal notranslate\">REQUIRED_FIELDS</code> 必须包含用户模型上的所有必填字段，但 <em>不应</em> 包含 <code class=\"docutils literal notranslate\">USERNAME_FIELD</code> 或 <code class=\"docutils literal notranslate\">password</code>，因为这些字段总是会被提示。</p>\n</aside>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.CustomUser.is_active\">\n<span class=\"sig-name descname\">is_active</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.CustomUser.is_active\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>一个布尔属性，表示用户是否被认为是 “激活的”。 这个属性作为 <code class=\"docutils literal notranslate\">AbstractBaseUser</code> 的属性，默认为 <code class=\"docutils literal notranslate\">True</code>。你如何选择实现它将取决于你所选择的认证后端的细节。详情请参考内置用户模型的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.is_active\" title=\"django.contrib.auth.models.User.is_active\"><code class=\"xref py py-attr docutils literal notranslate\">is_active 属性的文档</code></a>。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.CustomUser.get_full_name\">\n<span class=\"sig-name descname\">get_full_name</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.CustomUser.get_full_name\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>可选项。用户的较长身份标识符，比如用户的全名。如果已经设置，则会与用户名一起出现在 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#module-django.contrib.admin\" title=\"django.contrib.admin: Django's admin site.\"><code class=\"xref py py-mod docutils literal notranslate\">django.contrib.admin</code></a> 中。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.CustomUser.get_short_name\">\n<span class=\"sig-name descname\">get_short_name</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.CustomUser.get_short_name\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>可选项。用户较短的身份标识符，比如用户的名。如果已经设置，它会在 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#module-django.contrib.admin\" title=\"django.contrib.admin: Django's admin site.\"><code class=\"xref py py-mod docutils literal notranslate\">django.contrib.admin</code></a> 页面头部的欢迎词中替换用户名。</p>\n</dd></dl>\n\n<aside class=\"admonition-importing-abstractbaseuser admonition\" role=\"note\">\n<p class=\"admonition-title\">导入 <code class=\"docutils literal notranslate\">AbstractBaseUser</code></p>\n<p><code class=\"docutils literal notranslate\">AbstractBaseUser</code> and <code class=\"docutils literal notranslate\">BaseUserManager</code> 可以从 <code class=\"docutils literal notranslate\">django.contrib.auth.base_user</code> 中导入，所以你无需在 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\">INSTALLED_APPS</code></a> 添加 <code class=\"docutils literal notranslate\">django.contrib.auth</code> 就能导入它们。</p>\n</aside>\n</dd></dl>\n\n<p><a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser\" title=\"django.contrib.auth.models.AbstractBaseUser\"><code class=\"xref py py-class docutils literal notranslate\">AbstractBaseUser</code></a> 的任何子类都可以使用下面的属性和方法：</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">models.</span><span class=\"sig-name descname\">AbstractBaseUser</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.get_username\">\n<span class=\"sig-name descname\">get_username</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.get_username\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回 <code class=\"docutils literal notranslate\">USERNAME_FIELD</code> 指定的字段的值。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.clean\">\n<span class=\"sig-name descname\">clean</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.clean\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>通过调用 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser.normalize_username\" title=\"django.contrib.auth.models.AbstractBaseUser.normalize_username\"><code class=\"xref py py-meth docutils literal notranslate\">normalize_username()</code></a> 来规范化用户名。 如果重写此方法，必须调用 <code class=\"docutils literal notranslate\">super()</code> 来保持规范化。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.get_email_field_name\">\n<em class=\"property\"><span class=\"k\">classmethod</span> </em><span class=\"sig-name descname\">get_email_field_name</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.get_email_field_name\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回由 <a class=\"reference internal\" href=\"#django.contrib.auth.models.CustomUser.EMAIL_FIELD\" title=\"django.contrib.auth.models.CustomUser.EMAIL_FIELD\"><code class=\"xref py py-attr docutils literal notranslate\">EMAIL_FIELD</code></a> 属性指定的电子邮件字段的名称。 如果未指定 <code class=\"docutils literal notranslate\">EMAIL_FIELD</code> ，则默认为 <code class=\"docutils literal notranslate\">'email'</code> 。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.normalize_username\">\n<em class=\"property\"><span class=\"k\">classmethod</span> </em><span class=\"sig-name descname\">normalize_username</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">username</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.normalize_username\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>应用 NFKC Unicode 规范化用户名，使得不同 Unicode 码位视觉相同字符视为相同。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.is_authenticated\">\n<span class=\"sig-name descname\">is_authenticated</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.is_authenticated\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>只读属性，始终返回 <code class=\"docutils literal notranslate\">True</code> （匿名用户 <code class=\"docutils literal notranslate\">AnonymousUser.is_authenticated</code>  始终返回 <code class=\"docutils literal notranslate\">False</code> ）。这是一种判断用户是否已通过身份验证的方法。这并不意味着任何权限，也不会检查用户是否处于活动状态或是否具有有效会话。即使通常您会根据 <code class=\"docutils literal notranslate\">request.user</code> 检查这个属性，以确定它是否被 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware\" title=\"django.contrib.auth.middleware.AuthenticationMiddleware\"><code class=\"xref py py-class docutils literal notranslate\">AuthenticationMiddleware</code></a> 填充（表示当前登录的用户），但是你应该知道该属性对于任何 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a> 实例都返回 <code class=\"docutils literal notranslate\">True</code>。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.is_anonymous\">\n<span class=\"sig-name descname\">is_anonymous</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.is_anonymous\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>只读属性总是 <code class=\"docutils literal notranslate\">False</code>。这个属性用于区分 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.AnonymousUser\" title=\"django.contrib.auth.models.AnonymousUser\"><code class=\"xref py py-class docutils literal notranslate\">AnonymousUser</code></a> 对象。通常情况下， <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.is_authenticated\" title=\"django.contrib.auth.models.User.is_authenticated\"><code class=\"xref py py-attr docutils literal notranslate\">is_authenticated</code></a> 应该置于只读。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.set_password\">\n<span class=\"sig-name descname\">set_password</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">raw_password</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.set_password\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>设置用户密码，谨慎保存密码哈希。不可保存 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser\" title=\"django.contrib.auth.models.AbstractBaseUser\"><code class=\"xref py py-class docutils literal notranslate\">AbstractBaseUser</code></a> 的对象。</p>\n<p>当 raw_password 为 <code class=\"docutils literal notranslate\">None</code> 时，密码将被设置为不可用的密码，就像 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser.set_unusable_password\" title=\"django.contrib.auth.models.AbstractBaseUser.set_unusable_password\"><code class=\"xref py py-meth docutils literal notranslate\">set_unusable_password()</code></a> 一样。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.check_password\">\n<span class=\"sig-name descname\">check_password</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">raw_password</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.check_password\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果给定的原始字符串是用户的正确密码，返回 <code class=\"docutils literal notranslate\">True</code>。（在进行比较时，这将处理密码散列。）</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.set_unusable_password\">\n<span class=\"sig-name descname\">set_unusable_password</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.set_unusable_password\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>将该用户标记为没有设置密码。 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser.check_password\" title=\"django.contrib.auth.models.AbstractBaseUser.check_password\"><code class=\"xref py py-meth docutils literal notranslate\">check_password()</code></a> 对这个用户的检查永远不会返回 <code class=\"docutils literal notranslate\">True</code>。不保存 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser\" title=\"django.contrib.auth.models.AbstractBaseUser\"><code class=\"xref py py-class docutils literal notranslate\">AbstractBaseUser</code></a> 对象。</p>\n<p>如果你的应用程序的身份验证是针对现有的外部源（如 LDAP 目录）进行的，你可能需要这个功能。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.has_usable_password\">\n<span class=\"sig-name descname\">has_usable_password</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.has_usable_password\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser.set_unusable_password\" title=\"django.contrib.auth.models.AbstractBaseUser.set_unusable_password\"><code class=\"xref py py-meth docutils literal notranslate\">set_unusable_password()</code></a> 被调用，返回 <code class=\"docutils literal notranslate\">False</code>。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash\">\n<span class=\"sig-name descname\">get_session_auth_hash</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回密码字段的 HMAC。用于 <span class=\"xref std std-ref\">session-invalidation-onpassword-change</span>。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractBaseUser.get_session_auth_fallback_hash\">\n<span class=\"sig-name descname\">get_session_auth_fallback_hash</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractBaseUser.get_session_auth_fallback_hash\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><aside class=\"version-note version-added\" data-version=\"4.1.8\" role=\"note\">\n<p class=\"version-note-title\">New in Django 4.1.8</p></aside>\n<p>Yields the HMAC of the password field using\n<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-SECRET_KEY_FALLBACKS\"><code class=\"xref std std-setting docutils literal notranslate\">SECRET_KEY_FALLBACKS</code></a>. Used by <code class=\"docutils literal notranslate\">get_user()</code>.</p>\n</dd></dl>\n\n</dd></dl>\n\n<p><a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractUser\" title=\"django.contrib.auth.models.AbstractUser\"><code class=\"xref py py-class docutils literal notranslate\">AbstractUser</code></a> 是 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser\" title=\"django.contrib.auth.models.AbstractBaseUser\"><code class=\"xref py py-class docutils literal notranslate\">AbstractBaseUser</code></a> 的子类。</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractUser\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">models.</span><span class=\"sig-name descname\">AbstractUser</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractUser\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.AbstractUser.clean\">\n<span class=\"sig-name descname\">clean</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.AbstractUser.clean\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>通过调用 <a class=\"reference internal\" href=\"#django.contrib.auth.models.BaseUserManager.normalize_email\" title=\"django.contrib.auth.models.BaseUserManager.normalize_email\"><code class=\"xref py py-meth docutils literal notranslate\">BaseUserManager.normalize_email()</code></a> 来规范化邮件。如果你覆盖了这个方法，一定要调用 <code class=\"docutils literal notranslate\">super()</code> 来保留规范化。</p>\n</dd></dl>\n\n</dd></dl>\n\n</section>\n<section id=\"writing-a-manager-for-a-custom-user-model\">\n<h3>为自定义的用户模型编写一个管理器<a class=\"heading-anchor\" href=\"#writing-a-manager-for-a-custom-user-model\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>你也该为你的用户模型定义一个自定义管理器。如果你的用户模型定义了和默认用户相同的 <code class=\"docutils literal notranslate\">username</code>, <code class=\"docutils literal notranslate\">email</code>, <code class=\"docutils literal notranslate\">is_staff</code>, <code class=\"docutils literal notranslate\">is_active</code>, <code class=\"docutils literal notranslate\">is_superuser</code>, <code class=\"docutils literal notranslate\">last_login</code>, 和 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>date_joined`等字段，你可以安装 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.UserManager\" title=\"django.contrib.auth.models.UserManager\"><code class=\"xref py py-class docutils literal notranslate\">UserManager</code></a> ；但是，如果你的用户模型还定义了其他字段，那么就需要定义一个自定义管理器，它扩展了 <a class=\"reference internal\" href=\"#django.contrib.auth.models.BaseUserManager\" title=\"django.contrib.auth.models.BaseUserManager\"><code class=\"xref py py-class docutils literal notranslate\">BaseUserManager</code></a> ，提供了两个额外的方法：</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.CustomUserManager\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">models.</span><span class=\"sig-name descname\">CustomUserManager</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.CustomUserManager\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.CustomUserManager.create_user\">\n<span class=\"sig-name descname\">create_user</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">username_field</em>, <em class=\"sig-param\">password<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>other_fields</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.CustomUserManager.create_user\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p><code class=\"docutils literal notranslate\">create_user()</code> 的原型应该接受username字段，加上其他所有必须的字段作为参数。举例，如果你的用户模型使用 <code class=\"docutils literal notranslate\">email</code> 作为用户名字段，<code class=\"docutils literal notranslate\">date_of_birth</code>  字段作为必填字段，那么 <code class=\"docutils literal notranslate\">create_user</code> 应该如下定义：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span> <span class=\"nf\">create_user</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> email<span class=\"p\">,</span> date_of_birth<span class=\"p\">,</span> password<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n    <span class=\"c1\"># create user here</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.CustomUserManager.create_superuser\">\n<span class=\"sig-name descname\">create_superuser</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">username_field</em>, <em class=\"sig-param\">password<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\"><span class=\"o\">**</span>other_fields</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.CustomUserManager.create_superuser\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p><code class=\"docutils literal notranslate\">create_superuser()</code> 的原型应该接受username字段，加上其他所有必须的字段作为参数。举例，如果你的用户模型使用 <code class=\"docutils literal notranslate\">email</code> 作为用户名字段，<code class=\"docutils literal notranslate\">date_of_birth</code> 字段作为必填字段，那么 <code class=\"docutils literal notranslate\">create_superuser</code> 应该如下定义：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span> <span class=\"nf\">create_superuser</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> email<span class=\"p\">,</span> date_of_birth<span class=\"p\">,</span> password<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n    <span class=\"c1\"># create superuser here</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n</dd></dl>\n\n</dd></dl>\n\n<p>对于 <a class=\"reference internal\" href=\"#django.contrib.auth.models.CustomUser.USERNAME_FIELD\" title=\"django.contrib.auth.models.CustomUser.USERNAME_FIELD\"><code class=\"xref py py-attr docutils literal notranslate\">USERNAME_FIELD</code></a> 或 <a class=\"reference internal\" href=\"#django.contrib.auth.models.CustomUser.REQUIRED_FIELDS\" title=\"django.contrib.auth.models.CustomUser.REQUIRED_FIELDS\"><code class=\"xref py py-attr docutils literal notranslate\">REQUIRED_FIELDS</code></a> 中的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/fields/#django.db.models.ForeignKey\" title=\"django.db.models.ForeignKey\"><code class=\"xref py py-class docutils literal notranslate\">ForeignKey</code></a> ，这些方法接收现有实例的:attr:~.ForeignKey.to_field （默认为 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/fields/#django.db.models.Field.primary_key\" title=\"django.db.models.Field.primary_key\"><code class=\"xref py py-attr docutils literal notranslate\">primary_key</code></a> ）的值。</p>\n<p><a class=\"reference internal\" href=\"#django.contrib.auth.models.BaseUserManager\" title=\"django.contrib.auth.models.BaseUserManager\"><code class=\"xref py py-class docutils literal notranslate\">BaseUserManager</code></a> 提供以下实用方法：</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.BaseUserManager\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">models.</span><span class=\"sig-name descname\">BaseUserManager</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.BaseUserManager\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.BaseUserManager.normalize_email\">\n<em class=\"property\"><span class=\"k\">classmethod</span> </em><span class=\"sig-name descname\">normalize_email</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">email</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.BaseUserManager.normalize_email\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>通过降低电子邮件地址的域部分来规范化电子邮件地址。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.BaseUserManager.get_by_natural_key\">\n<span class=\"sig-name descname\">get_by_natural_key</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">username</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.BaseUserManager.get_by_natural_key\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>使用 <code class=\"docutils literal notranslate\">USERNAME_FIELD</code> 指定的字段的内容检索用户实例。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.BaseUserManager.make_random_password\">\n<span class=\"sig-name descname\">make_random_password</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">length<span class=\"o\">=</span><span class=\"default_value\">10</span></em>, <em class=\"sig-param\">allowed_chars<span class=\"o\">=</span><span class=\"default_value\">'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.BaseUserManager.make_random_password\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回具有给定长度和给定字符串的随机密码。请注意， <code class=\"docutils literal notranslate\">allowed_chars</code>  的默认值不包含可能导致用户混淆的字母，包括：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">i</code>, <code class=\"docutils literal notranslate\">l</code>, <code class=\"docutils literal notranslate\">I</code>, 和 <code class=\"docutils literal notranslate\">1</code> (小写i, 小写L, 大写i和数字1)</p></li>\n<li><p><code class=\"docutils literal notranslate\">o</code>, <code class=\"docutils literal notranslate\">O</code>, 和 <code class=\"docutils literal notranslate\">0</code> (小写 o, 大写 o, 和数字0 )</p></li>\n</ul>\n</dd></dl>\n\n</dd></dl>\n\n</section>\n<section id=\"extending-django-s-default-user\">\n<h3>扩展Django的默认用户模型<a class=\"heading-anchor\" href=\"#extending-django-s-default-user\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>If you're entirely happy with Django's <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a>\nmodel, but you want to add some additional profile information, you could\nsubclass <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractUser\" title=\"django.contrib.auth.models.AbstractUser\"><code class=\"xref py py-class docutils literal notranslate\">django.contrib.auth.models.AbstractUser</code></a> and add your custom\nprofile fields, although we'd recommend a separate model as described in\n<a class=\"reference internal\" href=\"#specifying-custom-user-model\"><span class=\"std std-ref\">指定自定义用户模型</span></a>. <code class=\"docutils literal notranslate\">AbstractUser</code> provides the full\nimplementation of the default <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a> as an\n<a class=\"reference internal\" href=\"/zh-hans/4.1/topics/db/models/#abstract-base-classes\"><span class=\"std std-ref\">abstract model</span></a>.</p>\n</section>\n<section id=\"custom-users-and-the-built-in-auth-forms\">\n<span id=\"id2\"></span><h3>自定义用户和内建的auth表单<a class=\"heading-anchor\" href=\"#custom-users-and-the-built-in-auth-forms\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django的内置 :ref:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>forms ` 和 :ref:<a href=\"#id3\"><span class=\"problematic\" id=\"id4\">`</span></a>views ` 对他们正在使用的用户模型做了一些假设。</p>\n<p>以下表单与 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser\" title=\"django.contrib.auth.models.AbstractBaseUser\"><code class=\"xref py py-class docutils literal notranslate\">AbstractBaseUser</code></a> 的任何子类兼容：</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.forms.AuthenticationForm\" title=\"django.contrib.auth.forms.AuthenticationForm\"><code class=\"xref py py-class docutils literal notranslate\">AuthenticationForm</code></a>:  使用 <a class=\"reference internal\" href=\"#django.contrib.auth.models.CustomUser.USERNAME_FIELD\" title=\"django.contrib.auth.models.CustomUser.USERNAME_FIELD\"><code class=\"xref py py-attr docutils literal notranslate\">USERNAME_FIELD</code></a> 指定的username字段。</p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.forms.SetPasswordForm\" title=\"django.contrib.auth.forms.SetPasswordForm\"><code class=\"xref py py-class docutils literal notranslate\">SetPasswordForm</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.forms.PasswordChangeForm\" title=\"django.contrib.auth.forms.PasswordChangeForm\"><code class=\"xref py py-class docutils literal notranslate\">PasswordChangeForm</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.forms.AdminPasswordChangeForm\" title=\"django.contrib.auth.forms.AdminPasswordChangeForm\"><code class=\"xref py py-class docutils literal notranslate\">AdminPasswordChangeForm</code></a></p></li>\n</ul>\n<p>以下表单对用户模型进行了假设，如果满足这些假设，则可以按原样使用:</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.forms.PasswordResetForm\" title=\"django.contrib.auth.forms.PasswordResetForm\"><code class=\"xref py py-class docutils literal notranslate\">PasswordResetForm</code></a> ：假设用户模型有一个字段存储用户的电子邮件地址，其名称由 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser.get_email_field_name\" title=\"django.contrib.auth.models.AbstractBaseUser.get_email_field_name\"><code class=\"xref py py-meth docutils literal notranslate\">get_email_field_name()</code></a> 返回（默认为电子邮件），这个方法用来标识用户，以及名为``is_active``的布尔字段，防止非活动用户重置密码。</p></li>\n</ul>\n<p>最后，下面的表单和 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a> 绑定，如果需要和自定义的用户模型一起使用，则需要重写或者扩展。</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.forms.UserCreationForm\" title=\"django.contrib.auth.forms.UserCreationForm\"><code class=\"xref py py-class docutils literal notranslate\">UserCreationForm</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#django.contrib.auth.forms.UserChangeForm\" title=\"django.contrib.auth.forms.UserChangeForm\"><code class=\"xref py py-class docutils literal notranslate\">UserChangeForm</code></a></p></li>\n</ul>\n<p>如果自定义的用户模型是 <code class=\"docutils literal notranslate\">AbstractUser</code> 的子类，则可以使用下面的方式来扩展表单：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.forms</span> <span class=\"kn\">import</span> UserCreationForm\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> CustomUser\n\n<span class=\"k\">class</span> <span class=\"nc\">CustomUserCreationForm</span><span class=\"p\">(</span>UserCreationForm<span class=\"p\">):</span>\n\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">(</span>UserCreationForm<span class=\"o\">.</span>Meta<span class=\"p\">):</span>\n        model <span class=\"o\">=</span> CustomUser\n        fields <span class=\"o\">=</span> UserCreationForm<span class=\"o\">.</span>Meta<span class=\"o\">.</span>fields <span class=\"o\">+</span> <span class=\"p\">(</span><span class=\"s1\">&#39;custom_field&#39;</span><span class=\"p\">,)</span>\n</code></pre></div>\n</section>\n<section id=\"custom-users-and-django-contrib-admin\">\n<h3>自定义用户和 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#module-django.contrib.admin\" title=\"django.contrib.admin: Django's admin site.\"><code class=\"xref py py-mod docutils literal notranslate\">django.contrib.admin</code></a><a class=\"heading-anchor\" href=\"#custom-users-and-django-contrib-admin\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你希望自定义的用户模型也与管理后台一起使用，那么你的用户模型必须定义一些额外的属性和方法。这些方法允许管理员控制用户对管理后台内容的访问：</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">models.</span><span class=\"sig-name descname\">CustomUser</span></dt>\n<dd></dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.is_staff\">\n<span class=\"sig-name descname\">is_staff</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.is_staff\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果允许用户有访问 admin 页面就返回 <code class=\"docutils literal notranslate\">True</code>。</p>\n</dd></dl>\n\n<dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.is_active\">\n<span class=\"sig-name descname\">is_active</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.is_active\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回``True``，如果该用户的账号当前是激活状态</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\">\n<span class=\"sig-name descname\">has_perm(perm, obj=None):</span></dt>\n<dd><p>如果用户有指定的权限，则返回 <code class=\"docutils literal notranslate\">True</code> 。如果提供了参数 <code class=\"docutils literal notranslate\">obj</code>  ，则需要对指定的对象实例进行权限检查。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\">\n<span class=\"sig-name descname\">has_module_perms(app_label):</span></dt>\n<dd><p>如果用户有权限访问指定 app 里的模型，那么返回 <code class=\"docutils literal notranslate\">True</code> 。</p>\n</dd></dl>\n\n<p>你也需要在 admin 文件里注册自定义的用户模型。如果自定义的用户模型扩展了  <code class=\"docutils literal notranslate\">django.contrib.auth.models.AbstractUser</code> ，你可以直接使用Django已有的类 <code class=\"docutils literal notranslate\">django.contrib.auth.admin.UserAdmin</code> 。如果你的用户模型扩展了 <a class=\"reference internal\" href=\"#django.contrib.auth.models.AbstractBaseUser\" title=\"django.contrib.auth.models.AbstractBaseUser\"><code class=\"xref py py-class docutils literal notranslate\">AbstractBaseUser</code></a> ，你将需要定义一个自定义的类 <code class=\"docutils literal notranslate\">ModelAdmin</code> 。不管怎样，你都将需要重写任何引用 <code class=\"docutils literal notranslate\">django.contrib.auth.models.AbstractUser</code> 上的字段的定义，这些字段不在你自定义的用户类中。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>如果正在使用自定义的 <code class=\"docutils literal notranslate\">ModelAdmin</code> 是 <code class=\"docutils literal notranslate\">django.contrib.auth.admin.UserAdmin</code> 的子类，那么你需要添加自定义字段到 <code class=\"docutils literal notranslate\">fieldsets</code> （用于在编辑用户中使用）和 <code class=\"docutils literal notranslate\">add_fieldsets</code> （用于在创建用户时使用）。比如</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.admin</span> <span class=\"kn\">import</span> UserAdmin\n\n<span class=\"k\">class</span> <span class=\"nc\">CustomUserAdmin</span><span class=\"p\">(</span>UserAdmin<span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n    fieldsets <span class=\"o\">=</span> UserAdmin<span class=\"o\">.</span>fieldsets <span class=\"o\">+</span> <span class=\"p\">(</span>\n        <span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;fields&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s1\">&#39;custom_field&#39;</span><span class=\"p\">,)}),</span>\n    <span class=\"p\">)</span>\n    add_fieldsets <span class=\"o\">=</span> UserAdmin<span class=\"o\">.</span>add_fieldsets <span class=\"o\">+</span> <span class=\"p\">(</span>\n        <span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;fields&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s1\">&#39;custom_field&#39;</span><span class=\"p\">,)}),</span>\n    <span class=\"p\">)</span>\n</code></pre></div>\n<p>查看 <a class=\"reference internal\" href=\"#custom-users-admin-full-example\"><span class=\"std std-ref\">a full example</span></a> 来了解更多细节。</p>\n</aside>\n</section>\n<section id=\"custom-users-and-permissions\">\n<h3>自定义用户和权限。<a class=\"heading-anchor\" href=\"#custom-users-and-permissions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>为了便于将Django的权限框架引入到你自己的用户类中，Django提供了 <a class=\"reference internal\" href=\"#django.contrib.auth.models.PermissionsMixin\" title=\"django.contrib.auth.models.PermissionsMixin\"><code class=\"xref py py-class docutils literal notranslate\">PermissionsMixin</code></a> 。这是一个抽象模型，可以包含在用户模型的类层次结构中，为你提供支持Django权限模型所需的所有方法和数据库字段。</p>\n<p><a class=\"reference internal\" href=\"#django.contrib.auth.models.PermissionsMixin\" title=\"django.contrib.auth.models.PermissionsMixin\"><code class=\"xref py py-class docutils literal notranslate\">PermissionsMixin</code></a> 提供下列方法和属性：</p>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.PermissionsMixin\">\n<em class=\"property\"><span class=\"k\">class</span> </em><span class=\"sig-prename descclassname\">models.</span><span class=\"sig-name descname\">PermissionsMixin</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.PermissionsMixin\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><dl class=\"py attribute\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.PermissionsMixin.is_superuser\">\n<span class=\"sig-name descname\">is_superuser</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.PermissionsMixin.is_superuser\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>布尔值。指定该用户拥有所有权限，而不用一个个开启权限。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.PermissionsMixin.get_user_permissions\">\n<span class=\"sig-name descname\">get_user_permissions</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">obj<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.PermissionsMixin.get_user_permissions\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回用户本身就自带的权限字符串集合。</p>\n<p>如果传入了 <code class=\"docutils literal notranslate\">obj</code> ，则只返回指定对象的用户权限。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.PermissionsMixin.get_group_permissions\">\n<span class=\"sig-name descname\">get_group_permissions</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">obj<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.PermissionsMixin.get_group_permissions\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回用户拥有权限的字符串集合，从用户所属组的权限中获取。</p>\n<p>如果传入 <code class=\"docutils literal notranslate\">obj</code> 参数，则只返回指定对象所属组的权限。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.PermissionsMixin.get_all_permissions\">\n<span class=\"sig-name descname\">get_all_permissions</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">obj<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.PermissionsMixin.get_all_permissions\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>返回用户拥有权限的字符串集合，同时从用户所属组及用户本身的权限中获取。</p>\n<p>如果传入 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>obj``参数，则只返回指定对象和所属组的权限。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.PermissionsMixin.has_perm\">\n<span class=\"sig-name descname\">has_perm</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">perm</em>, <em class=\"sig-param\">obj<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.PermissionsMixin.has_perm\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果用户具有指定的权限，则返回 <code class=\"docutils literal notranslate\">True</code> ，其中 <code class=\"docutils literal notranslate\">perm</code> 的格式为 <code class=\"docutils literal notranslate\">&quot;&lt;app label&gt;.&lt;permission codename&gt;&quot;</code> (see <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/default/#topic-authorization\"><span class=\"std std-ref\">permissions</span></a>)。如果 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.is_active\" title=\"django.contrib.auth.models.User.is_active\"><code class=\"xref py py-attr docutils literal notranslate\">User.is_active</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.is_superuser\" title=\"django.contrib.auth.models.User.is_superuser\"><code class=\"xref py py-attr docutils literal notranslate\">is_superuser</code></a> 都为 <code class=\"docutils literal notranslate\">True</code>，则这个方法一直返回 <code class=\"docutils literal notranslate\">True</code> 。</p>\n<p>如果传入 <code class=\"docutils literal notranslate\">obj</code> 参数，则这个方法不会检查该模型权限，而只会检查这个出传入对象的权限。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.PermissionsMixin.has_perms\">\n<span class=\"sig-name descname\">has_perms</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">perm_list</em>, <em class=\"sig-param\">obj<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.PermissionsMixin.has_perms\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果用户具有指定权限列表里的每个权限，则返回 <code class=\"docutils literal notranslate\">True</code> ，其中perm的格式为 <code class=\"docutils literal notranslate\">&quot;&lt;app label&gt;.&lt;permission codename&gt;&quot;</code> 。如果 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.is_active\" title=\"django.contrib.auth.models.User.is_active\"><code class=\"xref py py-attr docutils literal notranslate\">User.is_active</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.is_superuser\" title=\"django.contrib.auth.models.User.is_superuser\"><code class=\"xref py py-attr docutils literal notranslate\">is_superuser</code></a> 都返回 <code class=\"docutils literal notranslate\">True</code> ，则这个方法一直返回 <code class=\"docutils literal notranslate\">True</code> 。</p>\n<p>如果传入参数  <code class=\"docutils literal notranslate\">obj</code>  ，则这个方法不会检查指定的权限列表，只检查指定对象的权限。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.auth.models.PermissionsMixin.has_module_perms\">\n<span class=\"sig-name descname\">has_module_perms</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">package_name</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.auth.models.PermissionsMixin.has_module_perms\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果用户拥有所给的 Django app 标签 (the Django app label) 里的任何权限，则会返回 <code class=\"docutils literal notranslate\">True</code> 。如果 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.is_active\" title=\"django.contrib.auth.models.User.is_active\"><code class=\"xref py py-attr docutils literal notranslate\">User.is_active</code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User.is_superuser\" title=\"django.contrib.auth.models.User.is_superuser\"><code class=\"xref py py-attr docutils literal notranslate\">is_superuser</code></a> 都为 <code class=\"docutils literal notranslate\">True</code> ，则该方法一直返回 <code class=\"docutils literal notranslate\">True</code> 。</p>\n</dd></dl>\n\n</dd></dl>\n\n<aside class=\"admonition-permissionsmixin-and-modelbackend admonition\" role=\"note\">\n<p class=\"admonition-title\"><code class=\"docutils literal notranslate\">PermissionsMixin</code>  和  <code class=\"docutils literal notranslate\">ModelBackend</code></p>\n<p>如果你没有引入 <a class=\"reference internal\" href=\"#django.contrib.auth.models.PermissionsMixin\" title=\"django.contrib.auth.models.PermissionsMixin\"><code class=\"xref py py-class docutils literal notranslate\">PermissionsMixin</code></a> ，必须确保没有调用 <code class=\"docutils literal notranslate\">ModelBackend</code> 的权限方法。<code class=\"docutils literal notranslate\">ModelBackend</code> 假定你的用户模型某些字段可用。如果你的用户模型没有提供这些字段，则当你检查权限的时候，会收到数据库错误提示。</p>\n</aside>\n</section>\n<section id=\"custom-users-and-proxy-models\">\n<h3>自定义用户和代理模型<a class=\"heading-anchor\" href=\"#custom-users-and-proxy-models\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>自定义用户模型的一个限制是安装自定义用户模型将破坏任何扩展  <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a> 的代理模型。代理模型必须基于具体的基类；通过定义自定义用户模型，你就移除了Django可靠地识别基类的功能。</p>\n<p>如果你的项目正在使用代理模型，你必须修改扩展用户模型的代理，或者把代理的行为都合并到 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/auth/#django.contrib.auth.models.User\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\">User</code></a> 子类里去。</p>\n</section>\n<section id=\"a-full-example\">\n<span id=\"custom-users-admin-full-example\"></span><h3>一个完整的例子<a class=\"heading-anchor\" href=\"#a-full-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>这里是一个兼容admin的自定义的用户app的例子。这个用户模型使用 email 地址作为username，并且生日是必填字段；除了用户账户上的 <code class=\"docutils literal notranslate\">admin</code> flag之外，它本身不提供权限检查。除用户创建的表单外，此模型和所有内置的身份验证表单和视图兼容。此例只是说明了大多数组件如何协同工作，不要直接复制到生产环境里。</p>\n<p>这段代码将一直存在于 <code class=\"docutils literal notranslate\">models.py</code> 文件中，用于自定义身份验证 app:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db</span> <span class=\"kn\">import</span> models\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.models</span> <span class=\"kn\">import</span> <span class=\"p\">(</span>\n    BaseUserManager<span class=\"p\">,</span> AbstractBaseUser\n<span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">MyUserManager</span><span class=\"p\">(</span>BaseUserManager<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">create_user</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> email<span class=\"p\">,</span> date_of_birth<span class=\"p\">,</span> password<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Creates and saves a User with the given email, date of</span>\n<span class=\"sd\">        birth and password.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> email<span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;Users must have an email address&#39;</span><span class=\"p\">)</span>\n\n        user <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>model<span class=\"p\">(</span>\n            email<span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span>normalize_email<span class=\"p\">(</span>email<span class=\"p\">),</span>\n            date_of_birth<span class=\"o\">=</span>date_of_birth<span class=\"p\">,</span>\n        <span class=\"p\">)</span>\n\n        user<span class=\"o\">.</span>set_password<span class=\"p\">(</span>password<span class=\"p\">)</span>\n        user<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span>_db<span class=\"p\">)</span>\n        <span class=\"k\">return</span> user\n\n    <span class=\"k\">def</span> <span class=\"nf\">create_superuser</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> email<span class=\"p\">,</span> date_of_birth<span class=\"p\">,</span> password<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Creates and saves a superuser with the given email, date of</span>\n<span class=\"sd\">        birth and password.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        user <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>create_user<span class=\"p\">(</span>\n            email<span class=\"p\">,</span>\n            password<span class=\"o\">=</span>password<span class=\"p\">,</span>\n            date_of_birth<span class=\"o\">=</span>date_of_birth<span class=\"p\">,</span>\n        <span class=\"p\">)</span>\n        user<span class=\"o\">.</span>is_admin <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        user<span class=\"o\">.</span>save<span class=\"p\">(</span>using<span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span>_db<span class=\"p\">)</span>\n        <span class=\"k\">return</span> user\n\n\n<span class=\"k\">class</span> <span class=\"nc\">MyUser</span><span class=\"p\">(</span>AbstractBaseUser<span class=\"p\">):</span>\n    email <span class=\"o\">=</span> models<span class=\"o\">.</span>EmailField<span class=\"p\">(</span>\n        verbose_name<span class=\"o\">=</span><span class=\"s1\">&#39;email address&#39;</span><span class=\"p\">,</span>\n        max_length<span class=\"o\">=</span><span class=\"mi\">255</span><span class=\"p\">,</span>\n        unique<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    date_of_birth <span class=\"o\">=</span> models<span class=\"o\">.</span>DateField<span class=\"p\">()</span>\n    is_active <span class=\"o\">=</span> models<span class=\"o\">.</span>BooleanField<span class=\"p\">(</span>default<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n    is_admin <span class=\"o\">=</span> models<span class=\"o\">.</span>BooleanField<span class=\"p\">(</span>default<span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n\n    objects <span class=\"o\">=</span> MyUserManager<span class=\"p\">()</span>\n\n    USERNAME_FIELD <span class=\"o\">=</span> <span class=\"s1\">&#39;email&#39;</span>\n    REQUIRED_FIELDS <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;date_of_birth&#39;</span><span class=\"p\">]</span>\n\n    <span class=\"k\">def</span> <span class=\"fm\">__str__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span>email\n\n    <span class=\"k\">def</span> <span class=\"nf\">has_perm</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> perm<span class=\"p\">,</span> obj<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"s2\">&quot;Does the user have a specific permission?&quot;</span>\n        <span class=\"c1\"># Simplest possible answer: Yes, always</span>\n        <span class=\"k\">return</span> <span class=\"kc\">True</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">has_module_perms</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> app_label<span class=\"p\">):</span>\n        <span class=\"s2\">&quot;Does the user have permissions to view the app `app_label`?&quot;</span>\n        <span class=\"c1\"># Simplest possible answer: Yes, always</span>\n        <span class=\"k\">return</span> <span class=\"kc\">True</span>\n\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span> <span class=\"nf\">is_staff</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"s2\">&quot;Is the user a member of staff?&quot;</span>\n        <span class=\"c1\"># Simplest possible answer: All admins are staff</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span>is_admin\n</code></pre></div>\n<p>然后，在 Django 管理后台里注册这个用户模型，下面这些代码必须在 app 的 <code class=\"docutils literal notranslate\">admin.py</code> 文件里：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django</span> <span class=\"kn\">import</span> forms\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib</span> <span class=\"kn\">import</span> admin\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.models</span> <span class=\"kn\">import</span> Group\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.admin</span> <span class=\"kn\">import</span> UserAdmin <span class=\"k\">as</span> BaseUserAdmin\n<span class=\"kn\">from</span> <span class=\"nn\">django.contrib.auth.forms</span> <span class=\"kn\">import</span> ReadOnlyPasswordHashField\n<span class=\"kn\">from</span> <span class=\"nn\">django.core.exceptions</span> <span class=\"kn\">import</span> ValidationError\n\n<span class=\"kn\">from</span> <span class=\"nn\">customauth.models</span> <span class=\"kn\">import</span> MyUser\n\n\n<span class=\"k\">class</span> <span class=\"nc\">UserCreationForm</span><span class=\"p\">(</span>forms<span class=\"o\">.</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;A form for creating new users. Includes all the required</span>\n<span class=\"sd\">    fields, plus a repeated password.&quot;&quot;&quot;</span>\n    password1 <span class=\"o\">=</span> forms<span class=\"o\">.</span>CharField<span class=\"p\">(</span>label<span class=\"o\">=</span><span class=\"s1\">&#39;Password&#39;</span><span class=\"p\">,</span> widget<span class=\"o\">=</span>forms<span class=\"o\">.</span>PasswordInput<span class=\"p\">)</span>\n    password2 <span class=\"o\">=</span> forms<span class=\"o\">.</span>CharField<span class=\"p\">(</span>label<span class=\"o\">=</span><span class=\"s1\">&#39;Password confirmation&#39;</span><span class=\"p\">,</span> widget<span class=\"o\">=</span>forms<span class=\"o\">.</span>PasswordInput<span class=\"p\">)</span>\n\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> MyUser\n        fields <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;email&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;date_of_birth&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">clean_password2</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Check that the two password entries match</span>\n        password1 <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>cleaned_data<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;password1&quot;</span><span class=\"p\">)</span>\n        password2 <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>cleaned_data<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;password2&quot;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> password1 <span class=\"ow\">and</span> password2 <span class=\"ow\">and</span> password1 <span class=\"o\">!=</span> password2<span class=\"p\">:</span>\n            <span class=\"k\">raise</span> ValidationError<span class=\"p\">(</span><span class=\"s2\">&quot;Passwords don&#39;t match&quot;</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> password2\n\n    <span class=\"k\">def</span> <span class=\"nf\">save</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> commit<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Save the provided password in hashed format</span>\n        user <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>save<span class=\"p\">(</span>commit<span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n        user<span class=\"o\">.</span>set_password<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>cleaned_data<span class=\"p\">[</span><span class=\"s2\">&quot;password1&quot;</span><span class=\"p\">])</span>\n        <span class=\"k\">if</span> commit<span class=\"p\">:</span>\n            user<span class=\"o\">.</span>save<span class=\"p\">()</span>\n        <span class=\"k\">return</span> user\n\n\n<span class=\"k\">class</span> <span class=\"nc\">UserChangeForm</span><span class=\"p\">(</span>forms<span class=\"o\">.</span>ModelForm<span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;A form for updating users. Includes all the fields on</span>\n<span class=\"sd\">    the user, but replaces the password field with admin&#39;s</span>\n<span class=\"sd\">    disabled password hash display field.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    password <span class=\"o\">=</span> ReadOnlyPasswordHashField<span class=\"p\">()</span>\n\n    <span class=\"k\">class</span> <span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        model <span class=\"o\">=</span> MyUser\n        fields <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;email&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;password&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;date_of_birth&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;is_active&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;is_admin&#39;</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">UserAdmin</span><span class=\"p\">(</span>BaseUserAdmin<span class=\"p\">):</span>\n    <span class=\"c1\"># The forms to add and change user instances</span>\n    form <span class=\"o\">=</span> UserChangeForm\n    add_form <span class=\"o\">=</span> UserCreationForm\n\n    <span class=\"c1\"># The fields to be used in displaying the User model.</span>\n    <span class=\"c1\"># These override the definitions on the base UserAdmin</span>\n    <span class=\"c1\"># that reference specific fields on auth.User.</span>\n    list_display <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;email&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;date_of_birth&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;is_admin&#39;</span><span class=\"p\">)</span>\n    list_filter <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;is_admin&#39;</span><span class=\"p\">,)</span>\n    fieldsets <span class=\"o\">=</span> <span class=\"p\">(</span>\n        <span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;fields&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s1\">&#39;email&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;password&#39;</span><span class=\"p\">)}),</span>\n        <span class=\"p\">(</span><span class=\"s1\">&#39;Personal info&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;fields&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s1\">&#39;date_of_birth&#39;</span><span class=\"p\">,)}),</span>\n        <span class=\"p\">(</span><span class=\"s1\">&#39;Permissions&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;fields&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s1\">&#39;is_admin&#39;</span><span class=\"p\">,)}),</span>\n    <span class=\"p\">)</span>\n    <span class=\"c1\"># add_fieldsets is not a standard ModelAdmin attribute. UserAdmin</span>\n    <span class=\"c1\"># overrides get_fieldsets to use this attribute when creating a user.</span>\n    add_fieldsets <span class=\"o\">=</span> <span class=\"p\">(</span>\n        <span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;classes&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s1\">&#39;wide&#39;</span><span class=\"p\">,),</span>\n            <span class=\"s1\">&#39;fields&#39;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s1\">&#39;email&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;date_of_birth&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;password1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;password2&#39;</span><span class=\"p\">),</span>\n        <span class=\"p\">}),</span>\n    <span class=\"p\">)</span>\n    search_fields <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;email&#39;</span><span class=\"p\">,)</span>\n    ordering <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;email&#39;</span><span class=\"p\">,)</span>\n    filter_horizontal <span class=\"o\">=</span> <span class=\"p\">()</span>\n\n\n<span class=\"c1\"># Now register the new UserAdmin...</span>\nadmin<span class=\"o\">.</span>site<span class=\"o\">.</span>register<span class=\"p\">(</span>MyUser<span class=\"p\">,</span> UserAdmin<span class=\"p\">)</span>\n<span class=\"c1\"># ... and, since we&#39;re not using Django&#39;s built-in permissions,</span>\n<span class=\"c1\"># unregister the Group model from admin.</span>\nadmin<span class=\"o\">.</span>site<span class=\"o\">.</span>unregister<span class=\"p\">(</span>Group<span class=\"p\">)</span>\n</code></pre></div>\n<p>最后，在项目配置文件中的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\">AUTH_USER_MODEL</code></a> 里指定自定义的用户模型为默认的用户模型。</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code>AUTH_USER_MODEL <span class=\"o\">=</span> <span class=\"s1\">&#39;customauth.MyUser&#39;</span>\n</code></pre></div>\n</section>\n</section>","rootId":"customizing-authentication-in-django","toc":[{"title":"其它认证资源","anchor":"other-authentication-sources","children":[{"title":"指定认证后端","anchor":"specifying-authentication-backends","children":[]},{"title":"编写一个认证后端","anchor":"writing-an-authentication-backend","children":[]},{"title":"在自定义后端处理认证","anchor":"handling-authorization-in-custom-backends","children":[{"title":"匿名用户的授权","anchor":"authorization-for-anonymous-users","children":[]},{"title":"非激活用户认证","anchor":"authorization-for-inactive-users","children":[]},{"title":"处理对象权限","anchor":"handling-object-permissions","children":[]}]}]},{"title":"自定义权限","anchor":"custom-permissions","children":[]},{"title":"扩展现有的 User 模型","anchor":"extending-the-existing-user-model","children":[]},{"title":"替换一个自定义的 User 模型。","anchor":"substituting-a-custom-user-model","children":[{"title":"启动项目时使用自定义用户模型","anchor":"using-a-custom-user-model-when-starting-a-project","children":[]},{"title":"在项目中更改为自定义用户模型。","anchor":"changing-to-a-custom-user-model-mid-project","children":[]},{"title":"可重用应用和 AUTH_USER_MODEL","anchor":"reusable-apps-and-auth-user-model","children":[]},{"title":"引用 User 模型","anchor":"referencing-the-user-model","children":[]},{"title":"指定自定义用户模型","anchor":"specifying-a-custom-user-model","children":[]},{"title":"为自定义的用户模型编写一个管理器","anchor":"writing-a-manager-for-a-custom-user-model","children":[]},{"title":"扩展Django的默认用户模型","anchor":"extending-django-s-default-user","children":[]},{"title":"自定义用户和内建的auth表单","anchor":"custom-users-and-the-built-in-auth-forms","children":[]},{"title":"自定义用户和 django.contrib.admin","anchor":"custom-users-and-django-contrib-admin","children":[]},{"title":"自定义用户和权限。","anchor":"custom-users-and-permissions","children":[]},{"title":"自定义用户和代理模型","anchor":"custom-users-and-proxy-models","children":[]},{"title":"一个完整的例子","anchor":"a-full-example","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/4.1/topics/"},{"docname":"topics/auth/index","title":"Django中的用户认证","url":"/zh-hans/4.1/topics/auth/"}],"prev":{"docname":"topics/auth/passwords","title":"Django中的密码管理","url":"/zh-hans/4.1/topics/auth/passwords/"},"next":{"docname":"topics/cache","title":"Django 缓存框架","url":"/zh-hans/4.1/topics/cache/"},"formats":{"html":"/zh-hans/4.1/topics/auth/customizing/","markdown":"/zh-hans/4.1/topics/auth/customizing.md","json":"/zh-hans/4.1/topics/auth/customizing.json"},"source":"https://github.com/django/django/blob/stable/4.1.x/docs/topics/auth/customizing.txt","official":"https://docs.djangoproject.com/zh-hans/4.1/topics/auth/customizing/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}