{"title":"Django 中的自定义验证","version":"2.1","locale":"zh-hans","docname":"topics/auth/customizing","url":"/zh-hans/2.1/topics/auth/customizing/","canonical":"https://djangodocs.dev/zh-hans/2.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>&lt;authentication-backends&gt;当用户模型中存储的用户名和密码需要不同于Django默认服务的验证时，提供了一个可扩展系统。</p>\n<p>你可以给你的模型 <a class=\"reference internal\" href=\"#custom-permissions\"><span class=\"std std-ref\">定制权限</span></a> 并且可以被Django的授权系统通过检查。</p>\n<p>你可以 :ref:` 扩展 &lt;extending-user&gt; ` 默认的 <code class=\"docutils literal notranslate\"><span class=\"pre\">User</span></code> 模型，或者完全自定义一个模型进行 :ref:` 替换 &lt;auth-custom-user&gt;`</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>请参阅&lt;authentication-backends-reference&gt;身份验证后端引用，有关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维护一个“身份验证后端”列表，用于检查身份验证。当有人调用:func:django.contrib.auth.authenticate() - 如下所示:ref:如何在`用户登录&lt;how-to-log-a-user-in&gt; - Django尝试所有身份验证后端进行身份验证。如果第一个验证方法失败，Django会尝试第二个验证方法，依此类推，直到所有后端都被尝试。</p>\n<p>在设置：<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>AUTHENTICATION_BACKENDS`设置中指定要使用的身份验证后端列表。这应该是一个Python路径名列表，指向知道如何进行身份验证的Python类。这些类可以在你的Python路径上的任何地方。</p>\n<p>默认， :setting:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>AUTHENTICATION_BACKENDS`设定为:</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>Django 的默认后台只检查其数据库和内置权限，并不提供任何登录限制机制来防止暴力登录攻击。如果需要抵制暴力登录攻击，需要自己在后台实现登录限制机制，或者使用 Web 服务器提供的保护机制。</p>\n<p>:setting:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>AUTHENTICATION_BACKENDS`是有序的，如果相同的用户名和密码对于多个后端都是合法的，那么 Django 会优先使用其中的第一个后端，而不会再处理后面的后端。</p>\n<p>如果一个后端抛出 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/exceptions/#django.core.exceptions.PermissionDenied\" title=\"django.core.exceptions.PermissionDenied\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">PermissionDenied</span></code></a> 异常，则验证流程立马终止，Django 不会继续检查其后的后端。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>一旦用户通过验证，Django 会将之前用于验证该用户的后端保存在用户的 session 中，以便在将来（session 有效期内）需要访问当前已验证的用户时可以重用该后端。这个优化意味着在 session 中缓存了验证后端的源代码，因此，如果你修改了 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/settings/#std-setting-AUTHENTICATION_BACKENDS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTHENTICATION_BACKENDS</span></code></a> 同时希望使用另外的方法重新验证用户，那么需要清除 session 数据。清除 session 数据的一个简单方法是执行 <code class=\"docutils literal notranslate\"><span class=\"pre\">Session.objects.all().delete()</span></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>一个验证后端其实就是一个 class，它实现了两个必要的方法：<code class=\"docutils literal notranslate\"><span class=\"pre\">get_user(user_id)</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">authenticate(request,</span> <span class=\"pre\">**credentials)</span></code>，以及其它一系列可选的权限相关的方法:ref:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>authorization methods&lt;authorization_methods&gt; <a href=\"#id3\"><span class=\"problematic\" id=\"id4\">`</span></a>.</p>\n<p>&quot;get_user&quot;方法的参数是&quot;user_id&quot;，并返回一个user对象或None。参数user_id也可能是username、数据库id，或者其他值，但这个参数必须你的user对象的主键。</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">authenticate``方法接受</span> <span class=\"pre\">``request</span></code> 参数和 credentials 关键字参数，大多数情况下，该方法类似于下面的代码:</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=\"w\"> </span><span class=\"nc\">MyBackend</span><span class=\"p\">:</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">authenticate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">username</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">password</span><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>但它也可能验证一个Token，就像这样:</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=\"w\"> </span><span class=\"nc\">MyBackend</span><span class=\"p\">:</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">authenticate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">token</span><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\"><span class=\"pre\">authenticate()``都应该检查所获得的凭证，并当凭证有效时返回一个用户对象。当凭证无效时，应该返回``None</span></code>。</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">request</span></code> 是 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a> ，默认为 <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code> 如果没有被提供给 <a class=\"reference internal\" href=\"/zh-hans/2.1/topics/auth/default/#django.contrib.auth.authenticate\" title=\"django.contrib.auth.authenticate\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">authenticate()</span></code></a> (它把request传给后端).</p>\n<p>Django admin 和 Django <a class=\"reference internal\" href=\"/zh-hans/2.1/topics/auth/default/#user-objects\"><span class=\"std std-ref\">User object</span></a>. 紧密结合。最好的处理方式是为你后端的每一个用户都创建一个 Django <code class=\"docutils literal notranslate\"><span class=\"pre\">User</span></code> 。(例如, 你的 LDAP 目录、你的外部 SQL 数据库等等。) 你能写一个脚本来提前做这件事情，或者让你的 <code class=\"docutils literal notranslate\"><span class=\"pre\">authenticate</span></code> 方法在一个用户第一次登录时做这件事。</p>\n<p>下面是一段验证后端的示例代码，它通过在 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>settings.py``文件中定义的用户名和密码变量进行身份验证，并且当用户第一次验证时，创建一个Django的``User``对象。</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=\"w\"> </span><span class=\"nn\">django.conf</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">settings</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.hashers</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">check_password</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">User</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">SettingsBackend</span><span class=\"p\">:</span>\n<span class=\"w\">    </span><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=\"w\"> </span><span class=\"nf\">authenticate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">username</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"n\">login_valid</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">settings</span><span class=\"o\">.</span><span class=\"n\">ADMIN_LOGIN</span> <span class=\"o\">==</span> <span class=\"n\">username</span><span class=\"p\">)</span>\n        <span class=\"n\">pwd_valid</span> <span class=\"o\">=</span> <span class=\"n\">check_password</span><span class=\"p\">(</span><span class=\"n\">password</span><span class=\"p\">,</span> <span class=\"n\">settings</span><span class=\"o\">.</span><span class=\"n\">ADMIN_PASSWORD</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">login_valid</span> <span class=\"ow\">and</span> <span class=\"n\">pwd_valid</span><span class=\"p\">:</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">user</span> <span class=\"o\">=</span> <span class=\"n\">User</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">username</span><span class=\"o\">=</span><span class=\"n\">username</span><span class=\"p\">)</span>\n            <span class=\"k\">except</span> <span class=\"n\">User</span><span class=\"o\">.</span><span class=\"n\">DoesNotExist</span><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                <span class=\"n\">user</span> <span class=\"o\">=</span> <span class=\"n\">User</span><span class=\"p\">(</span><span class=\"n\">username</span><span class=\"o\">=</span><span class=\"n\">username</span><span class=\"p\">)</span>\n                <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">is_staff</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n                <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">is_superuser</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n                <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n            <span class=\"k\">return</span> <span class=\"n\">user</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_user</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">user_id</span><span class=\"p\">):</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">User</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">pk</span><span class=\"o\">=</span><span class=\"n\">user_id</span><span class=\"p\">)</span>\n        <span class=\"k\">except</span> <span class=\"n\">User</span><span class=\"o\">.</span><span class=\"n\">DoesNotExist</span><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/2.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\"><span class=\"pre\">get_group_permissions()</span></code></a>, <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">get_all_permissions()</span></code></a>, <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">has_perm()</span></code></a>, and <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">has_module_perms()</span></code></a>)委托给任何实现了这些函数的验证后端。</p>\n<p>用户所拥有的权限将是所有验证后端返回的所有权限的一个超集。也就是说，如果任何后端之一将一个权限赋予了用户，那么Django最终也将该权限赋予这个用户。</p>\n<p>如果一个后端在:meth:~django.contrib.auth.models.User.has_perm() 或 <code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">PermissionDenied()</span></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=\"w\"> </span><span class=\"nc\">SettingsBackend</span><span class=\"p\">:</span>\n    <span class=\"o\">...</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">has_perm</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">user_obj</span><span class=\"p\">,</span> <span class=\"n\">perm</span><span class=\"p\">,</span> <span class=\"n\">obj</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">user_obj</span><span class=\"o\">.</span><span class=\"n\">username</span> <span class=\"o\">==</span> <span class=\"n\">settings</span><span class=\"o\">.</span><span class=\"n\">ADMIN_LOGIN</span>\n</code></pre></div>\n<p>这将给予上例中被授权访问的用户以完全权限。注意，除了与对应的类 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.models.User</span></code> 函数相同的参数之外，后端的auth函数还接收user对象作为一个参数，这个user对象有可能是匿名user。</p>\n<p><a class=\"reference external\" href=\"https://github.com/django/django/blob/master/django/contrib/auth/backends.py\">django/contrib/auth/backend.py</a> 中的 <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelBackend</span></code> 类给出了鉴权机制的全部实现，这个类是默认的后端并且在大多时候都需要 <code class=\"docutils literal notranslate\"><span class=\"pre\">auth_permission</span></code> 表。若需要对部分后端API的行为进行自定义，可以利用Python的继承，定义 <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelBackend</span></code> 的子类，而不是在自定义后端中对所有API重新实现一遍。</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的权限框架并没有存储匿名用户的权限。然而，传给验证后端的用户对象可能是一个:class:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>django.contrib.auth.models.AnonymousUser`对象，使得后端可以自定义对匿名用户的验证。这对于那些编写可复用应用的作者来讲格外有用，因为他们可以将验证完全委托给验证后端，而不是通过设置。比如，当控制匿名访问的时候。</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>非活跃用户就是:attr:~django.contrib.auth.models.User.is_active`字段设置为``False``的用户。:class:`~django.contrib.auth.backends.ModelBackend 和:class:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>~django.contrib.auth.backends.RemoteUserBackend`验证后台禁止这些用户进行验证。如果用户有:attr:<a href=\"#id3\"><span class=\"problematic\" id=\"id4\">`</span></a>~django.contrib.auth.models.CustomUser.is_active`字段，则所有的用户都允许进行验证。</p>\n<p>如果你想用非活跃用户来验证，你可以使用：class: ~django.contrib.auth.backends.AllowAllUsersModelBackend 和：class: ~django.contrib.auth.backends.AllowAllUsersRemoteUserBackend</p>\n<p>权限系统支持匿名用户有权执行某些操作，而经过已验证的不活动用户则不能这样做。</p>\n<p>在你的后端permission方法中，不要忘记测试user的``is_active``属性。</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的权限框架为对象权限提供了基础，尽管在内核中没有实现它。这意味着检查对象权限将始终返回``False``或空列表（取决于所执行的检查）。身份验证后端将为每个对象相关的授权方法接收关键字参数``obj``和``user_obj``，并可以适当地返回对象级权限。</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>为给定的模型对象创建自定权限，使用 permission ， 参考： model Meta attribute&lt;meta-options&gt;</p>\n<p>这个示例中的 Task 模型创建了两个用户自定权限，即：用户能不能使用 Task 实例执行操作，这取决于你的应用要求。</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=\"w\"> </span><span class=\"nc\">Task</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n    <span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        <span class=\"n\">permissions</span> <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>当你运行:djadmin:manage.py migrate &lt;migrate&gt; 时，它只创建那些额外的权限。（创建权限的函数连接到:data:~django.db.models.signals.post_migrate 信号）。 你的代码负责在用户试图访问由应用程序提供的功能（查看任务（task），改变任务状态，关闭任务）时检查这些权限的值。继续上面的例子， 下面的语句检查是否一个用户能查看任务:</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=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">has_perm</span><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\"><span class=\"pre\">User</span></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>有两种方法可以扩展默认的User模型，而不需要用你的模型来替换它。如果你需要改变的只是行为，并且不需要改变数据库存储的内容，那么你可以建立一个基于User模型的代理模型。它允许代理模型提供很多功能，包括默认排序，自定义的管理器和自定义的模型方法等。</p>\n<p>如果你想存储与User模型关联的信息，可以使用OneToOneField到包含其他信息字段的模型。这种one-to-one模型经常被称作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=\"w\"> </span><span class=\"nn\">django.contrib.auth.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">User</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Employee</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">user</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">OneToOneField</span><span class=\"p\">(</span><span class=\"n\">User</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n    <span class=\"n\">department</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>假设一个既有用户又有雇员模型的现有雇员Fred Smith，您可以使用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><span class=\"n\">u</span> <span class=\"o\">=</span> <span class=\"n\">User</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">username</span><span class=\"o\">=</span><span class=\"s1\">&#39;fsmith&#39;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">freds_department</span> <span class=\"o\">=</span> <span class=\"n\">u</span><span class=\"o\">.</span><span class=\"n\">employee</span><span class=\"o\">.</span><span class=\"n\">department</span>\n</code></pre></div>\n<p>添加资料(Profile)模型到管理后台的用户页面，需要定义一个:class:~django.contrib.admin.InlineModelAdmin  (这个例子中，我们使用:class:~django.contrib.admin.StackedInline ) 到你的app里的``admin.py``中，并把它添加到``UserAdmin``后，向:class:~django.contrib.auth.models.User 类注册:</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=\"w\"> </span><span class=\"nn\">django.contrib</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">admin</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.admin</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">UserAdmin</span> <span class=\"k\">as</span> <span class=\"n\">BaseUserAdmin</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">User</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">my_user_profile_app.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Employee</span>\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=\"w\"> </span><span class=\"nc\">EmployeeInline</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">StackedInline</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Employee</span>\n    <span class=\"n\">can_delete</span> <span class=\"o\">=</span> <span class=\"kc\">False</span>\n    <span class=\"n\">verbose_name_plural</span> <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=\"w\"> </span><span class=\"nc\">UserAdmin</span><span class=\"p\">(</span><span class=\"n\">BaseUserAdmin</span><span class=\"p\">):</span>\n    <span class=\"n\">inlines</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">EmployeeInline</span><span class=\"p\">,)</span>\n\n<span class=\"c1\"># Re-register UserAdmin</span>\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">unregister</span><span class=\"p\">(</span><span class=\"n\">User</span><span class=\"p\">)</span>\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">User</span><span class=\"p\">,</span> <span class=\"n\">UserAdmin</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这些资料模型并不特殊，它们只是Django模型，用来一对一链接用户模型。因此，它们并不会在一个用户创立的时候自动生成，但可以使用 <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">django.db.models.signals.post_save</span></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\"><span class=\"pre\">User</span></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 href=\"#id1\"><span class=\"problematic\" id=\"id2\">:类:`~django.contrib.auth.models.User`</span></a> 模型 可能并不适合一些项目的身份验证需求。例如，在一些网站上使用邮件地址代替用户名来作为你的标识令牌更有意义。</p>\n<p>Django 允许你为引用了自定模型的：setting: AUTH_USER_MODEL 设置一个值来重写默认的用户表。</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=\"n\">AUTH_USER_MODEL</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;myapp.MyUser&#39;</span>\n</code></pre></div>\n<p>这个引号中描述的是Django应用的名称 ( 必须在你的配置`INSTALLED_APPS`里 )，和你希望当做用户模型的Django模型名称。</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=\"w\"> </span><span class=\"nn\">django.contrib.auth.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">AbstractUser</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">User</span><span class=\"p\">(</span><span class=\"n\">AbstractUser</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n</code></pre></div>\n<p>不要忘记将 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_USER_MODEL</span></code></a> 指向它。在创建任何迁移或者首次运行 <code class=\"docutils literal notranslate\"><span class=\"pre\">manage.py</span> <span class=\"pre\">migrate</span></code> 之前执行这个操作。</p>\n<p>同样的，在 app 中的 <code class=\"docutils literal notranslate\"><span class=\"pre\">admin.py</span></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=\"w\"> </span><span class=\"nn\">django.contrib</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">admin</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.admin</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">UserAdmin</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">User</span>\n\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">User</span><span class=\"p\">,</span> <span class=\"n\">UserAdmin</span><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/2.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_USER_MODEL</span></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/2.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_USER_MODEL</span></code></a> 引用的模型必须在第一次迁移的时候创建（通常被称作``0001_initial``）；否则，你将会遇到依赖问题。</p>\n<p>此外，在运行迁移时可能会遇到 <code class=\"docutils literal notranslate\"><span class=\"pre\">CircularDependencyError</span></code> ，因为Django由于动态依赖性而无法自动中断依赖循环。如果你遇到这个错误，则应通过移除依赖用户模型的其他模型，并进行二次迁移。（如果你想了解它通常是如何运行的，可以尝试建立两个相互指向彼此的外键的普通模型，并查看 <code class=\"docutils literal notranslate\"><span class=\"pre\">makemigrations</span></code> 如何解决该循环依赖关系。）</p>\n</section>\n<section id=\"reusable-apps-and-auth-user-model\">\n<h3>应用复用和 <code class=\"docutils literal notranslate\"><span class=\"pre\">AUTH_USER_MODEL</span></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>可复用的app不能实现实现一个自定义模型。一个项目可能有很多app，如果有两个可复用的app实现了自定义用户模型，他们就不能同时使用。如果你需要在你的app里保存每一个用户信息，可以像下面这样使用 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/models/fields/#django.db.models.ForeignKey\" title=\"django.db.models.ForeignKey\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ForeignKey</span></code></a> 或者 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/models/fields/#django.db.models.OneToOneField\" title=\"django.db.models.OneToOneField\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">OneToOneField</span></code></a> 指向 <code class=\"docutils literal notranslate\"><span class=\"pre\">settings.AUTH_USER_MODEL</span></code>  。</p>\n</section>\n<section id=\"referencing-the-user-model\">\n<h3>引用 <code class=\"docutils literal notranslate\"><span class=\"pre\">User</span></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/2.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_USER_MODEL</span></code></a> 已经指向了另一个用户模型后，如果你直接指向 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/contrib/auth/#id1\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></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\"><span class=\"pre\">get_user_model</span></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>你应该通过 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.get_user_model()</span></code> 来引用用户模型，而不是直接引用 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/contrib/auth/#id1\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></code></a> 。这个方法将返回当前可用的用户模型——如果指定了自定义用户模型，则返回自定义的模型，否则返回 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/contrib/auth/#id1\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></code></a> 。</p>\n<p>当你定义一个外键或多对多关系指向用户模型时，你应该指定自定义模型使用 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_USER_MODEL</span></code></a> setting 。举例来说：</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=\"w\"> </span><span class=\"nn\">django.conf</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">settings</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">models</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Article</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">author</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span>\n        <span class=\"n\">settings</span><span class=\"o\">.</span><span class=\"n\">AUTH_USER_MODEL</span><span class=\"p\">,</span>\n        <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n</code></pre></div>\n<p>当连接到用户模型发送的信号时，你应该使用 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_USER_MODEL</span></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=\"w\"> </span><span class=\"nn\">django.conf</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">settings</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models.signals</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">post_save</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">post_save_receiver</span><span class=\"p\">(</span><span class=\"n\">sender</span><span class=\"p\">,</span> <span class=\"n\">instance</span><span class=\"p\">,</span> <span class=\"n\">created</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"k\">pass</span>\n\n<span class=\"n\">post_save</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"n\">post_save_receiver</span><span class=\"p\">,</span> <span class=\"n\">sender</span><span class=\"o\">=</span><span class=\"n\">settings</span><span class=\"o\">.</span><span class=\"n\">AUTH_USER_MODEL</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>一般来说，最简单的指向用户模型的方法是在导入的时候设置 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_USER_MODEL</span></code></a> ，但是也可以调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_user_model()</span></code> ，因此你可以使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">models.ForeignKey(get_user_model(),</span> <span class=\"pre\">...)</span></code> 。</p>\n<p>如果你的app使用多个用户模型进行测试，例如使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">&#64;override_settings(AUTH_USER_MODEL=...)</span></code> ，并将get_user_model()的结果缓存在模块级变量中，则可能需要监听 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/signals/#django.test.signals.setting_changed\" title=\"django.test.signals.setting_changed\"><code class=\"xref py py-data docutils literal notranslate\"><span class=\"pre\">setting_changed</span></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=\"w\"> </span><span class=\"nn\">django.apps</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">apps</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_user_model</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.core.signals</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">setting_changed</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.dispatch</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">receiver</span>\n\n<span class=\"nd\">@receiver</span><span class=\"p\">(</span><span class=\"n\">setting_changed</span><span class=\"p\">)</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">user_model_swapped</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">kwargs</span><span class=\"p\">[</span><span class=\"s1\">&#39;setting&#39;</span><span class=\"p\">]</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;AUTH_USER_MODEL&#39;</span><span class=\"p\">:</span>\n        <span class=\"n\">apps</span><span class=\"o\">.</span><span class=\"n\">clear_cache</span><span class=\"p\">()</span>\n        <span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">myapp</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">some_module</span>\n        <span class=\"n\">some_module</span><span class=\"o\">.</span><span class=\"n\">UserModel</span> <span class=\"o\">=</span> <span class=\"n\">get_user_model</span><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<aside class=\"admonition-model-design-considerations admonition\">\n<p class=\"admonition-title\">Model 设计注意事项</p>\n<p>在处理与您的自定义用户模型中不直接与身份验证相关的信息之前要仔细考虑。</p>\n<p>在与用户模型有关系的模型中存储特定于应用程序的用户信息可能更好。这允许每个应用程序指定自己的用户数据需求，而不冒与其他应用程序发生冲突的风险。另一方面，检索此相关信息的查询将涉及数据库连接，这可能对性能产生影响。</p>\n</aside>\n<p>Django 希望你自定义的用户模型能够满足一些最低需求。</p>\n<p>如果使用默认身份验证后端，那么您的模型必须具有用于标识目的的唯一字段。这可以是用户名、电子邮件地址或任何其他唯一属性。如果使用可以支持它的自定义身份验证后端，则允许使用非唯一用户名字段。</p>\n<p>构造一个兼容的自定义用户模型的最简单方法是继承:class:~django.contrib.auth.models.AbstractBaseUser。:class:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>~django.contrib.auth.models.AbstractBaseUser`提供用户模型的核心实现，包括散列密码和标记化的密码重置。然后必须提供一些关键实现细节：</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\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">models.</span></span><span class=\"sig-name descname\"><span class=\"pre\">CustomUser</span></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\"><span class=\"pre\">USERNAME_FIELD</span></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>作为唯一标识符的描述用户模型字段名的字符串，通常是一个用户名，但也可以是一个电子邮件地址，或任何其他唯一标识符。该字段*必须*是唯一的（即定义了 <code class=\"docutils literal notranslate\"><span class=\"pre\">unique=True</span></code> ），除非你使用自定义身份验证后端，可以支持非唯一的用户名。</p>\n<p>接下来的样例中，<code class=\"docutils literal notranslate\"><span class=\"pre\">identifier</span></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=\"w\"> </span><span class=\"nc\">MyUser</span><span class=\"p\">(</span><span class=\"n\">AbstractBaseUser</span><span class=\"p\">):</span>\n    <span class=\"n\">identifier</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">40</span><span class=\"p\">,</span> <span class=\"n\">unique</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n    <span class=\"o\">...</span>\n    <span class=\"n\">USERNAME_FIELD</span> <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\"><span class=\"pre\">EMAIL_FIELD</span></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\"><span class=\"pre\">get_email_field_name()</span></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\"><span class=\"pre\">REQUIRED_FIELDS</span></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/2.1/ref/django-admin/#django-admin-createsuperuser\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">createsuperuser</span></code></a> 来创建用户时提示的必填字段列表。这个列表里的字段必须是非空或者未定义字段，也可以包含一些你想在创建用户时进行提示的附加字段。 <code class=\"docutils literal notranslate\"><span class=\"pre\">REQUIRED_FIELDS</span></code> 对Django的其他部分无效，比如在admin页面中创建用户。</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=\"w\"> </span><span class=\"nc\">MyUser</span><span class=\"p\">(</span><span class=\"n\">AbstractBaseUser</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n    <span class=\"n\">date_of_birth</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">DateField</span><span class=\"p\">()</span>\n    <span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">FloatField</span><span class=\"p\">()</span>\n    <span class=\"o\">...</span>\n    <span class=\"n\">REQUIRED_FIELDS</span> <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\"><span class=\"pre\">REQUIRED_FIELDS</span></code> 必须包含你的用户模型中所有的必填字段，但不用包含``USERNAME_FIELD`` 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">password</span></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\"><span class=\"pre\">is_active</span></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\"><span class=\"pre\">AbstractBaseUser</span></code> 的属性提供，默认是 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> 。如何去实现该属性的功能取决于你所选择的认证后端。查看 <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">is_active</span> <span class=\"pre\">attribute</span> <span class=\"pre\">on</span> <span class=\"pre\">the</span> <span class=\"pre\">built-in</span> <span class=\"pre\">user</span> <span class=\"pre\">model</span></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\"><span class=\"pre\">get_full_name</span></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/2.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\"><span class=\"pre\">django.contrib.admin</span></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\"><span class=\"pre\">get_short_name</span></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/2.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\"><span class=\"pre\">django.contrib.admin</span></code></a> 页面头部的欢迎词中替换用户名。</p>\n</dd></dl>\n\n<aside class=\"version-note version-changed\" data-version=\"2.0\">\n<p class=\"version-note-title\">Changed in Django 2.0</p><p>在旧版本中，当``AbstractBaseUser`` 实现了 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_short_name()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_full_name()</span></code> ，则子类也必须实现，否则会抛 <code class=\"docutils literal notranslate\"><span class=\"pre\">NotImplementedError</span></code> 异常。</p>\n</aside>\n<aside class=\"admonition-importing-abstractbaseuser admonition\">\n<p class=\"admonition-title\">引入 <code class=\"docutils literal notranslate\"><span class=\"pre\">AbstractBaseUser</span></code></p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">AbstractBaseUser</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">BaseUserManager</span></code> 可以从 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.base_user</span></code> 中导入，所以你无需在 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">INSTALLED_APPS</span></code></a> 添加 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth</span></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\"><span class=\"pre\">AbstractBaseUser</span></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\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">models.</span></span><span class=\"sig-name descname\"><span class=\"pre\">AbstractBaseUser</span></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\"><span class=\"pre\">get_username</span></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\"><span class=\"pre\">USERNAME_FIELD</span></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\"><span class=\"pre\">clean</span></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\"><span class=\"pre\">normalize_username()</span></code></a> 来规范化用户名。 如果重写此方法，必须调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">super()</span></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\"><span class=\"pre\">classmethod</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">get_email_field_name</span></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\"><span class=\"pre\">EMAIL_FIELD</span></code></a> 属性指定的电子邮件字段的名称。 如果未指定 <code class=\"docutils literal notranslate\"><span class=\"pre\">EMAIL_FIELD</span></code> ，则默认为 <code class=\"docutils literal notranslate\"><span class=\"pre\">'email'</span></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\"><span class=\"pre\">classmethod</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">normalize_username</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">username</span></span></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\"><span class=\"pre\">is_authenticated</span></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\"><span class=\"pre\">True</span></code> （匿名用户 <code class=\"docutils literal notranslate\"><span class=\"pre\">AnonymousUser.is_authenticated</span></code>  始终返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code> ）。这是一种判断用户是否已通过身份验证的方法。这并不意味着任何权限，也不会检查用户是否处于活动状态或是否具有有效会话。即使通常您会根据 <code class=\"docutils literal notranslate\"><span class=\"pre\">request.user</span></code> 检查这个属性，以确定它是否被 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware\" title=\"django.contrib.auth.middleware.AuthenticationMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">AuthenticationMiddleware</span></code></a> 填充（表示当前登录的用户），但是你应该知道该属性对于任何 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/contrib/auth/#id1\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></code></a> 实例都返回True。</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\"><span class=\"pre\">is_anonymous</span></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>只读属性总是'False'。这个属性用于区分类:model.User和model.AnonymousUser对象。通常情况下，属性:'model.User.is_authenticated'应该置于只读。</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\"><span class=\"pre\">set_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">raw_password</span></span></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>设置用户密码，谨慎保存密码哈希。不可保存类'django.conrtib.auth.models.AbstractBaseUser’的对象。</p>\n<p>如果密码为空，密码应设置为不可用密码。例如可以使用方法:django.contrib.auth.mode.Is.AbstractBaseUser.set_unusable_password()。</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\"><span class=\"pre\">check_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">raw_password</span></span></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>如果密码正确则返回'True'。(密码哈希值用于比较)</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\"><span class=\"pre\">set_unusable_password</span></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\"><span class=\"pre\">check_password()</span></code></a> 此用户将永远不会返回True。 不保存 <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\"><span class=\"pre\">AbstractBaseUser</span></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\"><span class=\"pre\">has_usable_password</span></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>如果方法'django.contrib.auth.models.AbstractBaseUser.set_unusable_password()'被调用则返回'False'。</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\"><span class=\"pre\">get_session_auth_hash</span></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。用于密码更改后会话失效。</p>\n</dd></dl>\n\n</dd></dl>\n\n<p>类:'models.AbstractUser是类:‘models.AbstractBaseUser’的子类。</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\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">models.</span></span><span class=\"sig-name descname\"><span class=\"pre\">AbstractUser</span></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\"><span class=\"pre\">clean</span></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>调用方法:‘BaseUserManger.normalize_email’来标准化邮件。如果你要重写这个方法，确保调用super()以保持标准化。</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>你应该为你的用户模型定义一个自定义管理器。如果你的用户模型定义了`username``, <code class=\"docutils literal notranslate\"><span class=\"pre\">email</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">is_staff</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">is_active</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">is_superuser</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">last_login</span></code>, and <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>date_joined`等变量域，这些变量Django均内置了。你只需要安装类:'django.contrib.auth,models.UserManager'；但是，如果你的用户模型还定义了其他的变量，那么你就需要扩展类:django.contrib.auth.models.BaseUserManager'，这个类提供了额外的两个方法。</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\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">models.</span></span><span class=\"sig-name descname\"><span class=\"pre\">CustomUserManager</span></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\"><span class=\"pre\">create_user</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">*username_field*</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password=None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">\\**other_fields</span></span></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\"><span class=\"pre\">create_user()</span></code> 的原型应该接受username字段，加上其他所有必须的字段作为参数。举例，如果你的用户模型使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">email</span></code> 作为用户名字段，<code class=\"docutils literal notranslate\"><span class=\"pre\">date_of_birth</span></code>  字段作为必填字段，那么 <code class=\"docutils literal notranslate\"><span class=\"pre\">create_user</span></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=\"w\"> </span><span class=\"nf\">create_user</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">email</span><span class=\"p\">,</span> <span class=\"n\">date_of_birth</span><span class=\"p\">,</span> <span class=\"n\">password</span><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\"><span class=\"pre\">create_superuser</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">*username_field*</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">password</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">\\**other_fields</span></span></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\"><span class=\"pre\">create_superuser()</span></code> 的原型应该接受username字段，加上其他所有必须的字段作为参数。举例，如果你的用户模型使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">email</span></code> 作为用户名字段，<code class=\"docutils literal notranslate\"><span class=\"pre\">date_of_birth</span></code> 字段作为必填字段，那么 <code class=\"docutils literal notranslate\"><span class=\"pre\">create_superuser</span></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=\"w\"> </span><span class=\"nf\">create_superuser</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">email</span><span class=\"p\">,</span> <span class=\"n\">date_of_birth</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"p\">):</span>\n    <span class=\"c1\"># create superuser here</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n<p>和 <code class=\"docutils literal notranslate\"><span class=\"pre\">create_user()</span></code> 不同的是，<code class=\"docutils literal notranslate\"><span class=\"pre\">create_superuser()</span></code> 要求调用者 <em>必须</em> 提供一个密码。</p>\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\"><span class=\"pre\">USERNAME_FIELD</span></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\"><span class=\"pre\">REQUIRED_FIELDS</span></code></a> 中的 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/models/fields/#django.db.models.ForeignKey\" title=\"django.db.models.ForeignKey\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ForeignKey</span></code></a> ，这些方法接收现有实例的:attr:~.ForeignKey.to_field`（默认为 :attr:`~django.db.models.Field.primary_key ）的值。</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\"><span class=\"pre\">BaseUserManager</span></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\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">models.</span></span><span class=\"sig-name descname\"><span class=\"pre\">BaseUserManager</span></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\"><span class=\"pre\">classmethod</span></span><span class=\"w\"> </span></em><span class=\"sig-name descname\"><span class=\"pre\">normalize_email</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">email</span></span></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\"><span class=\"pre\">get_by_natural_key</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">username</span></span></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\"><span class=\"pre\">USERNAME_FIELD</span></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\"><span class=\"pre\">make_random_password</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">length</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">10</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">allowed_chars</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'</span></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\"><span class=\"pre\">allowed_chars</span></code>  的默认值不包含可能导致用户混淆的字母，包括：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">i</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">l</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">I</span></code>, 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">1</span></code> (小写i, 小写L, 大写i和数字1)</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">o</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">O</span></code>, 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">0</span></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>如果你对Django自带的用户模型完全满意，而你只想添加一些其他信息，你可以简单地继承 <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\"><span class=\"pre\">django.contrib.auth.models.AbstractUser</span></code></a>  并添加你的自定义字段，尽管我们建议使用在“模型设计考虑因素”中描述 <a class=\"reference internal\" href=\"#specifying-custom-user-model\"><span class=\"std std-ref\">指定自定义用户模型</span></a> 那样的单独的模型。  <code class=\"docutils literal notranslate\"><span class=\"pre\">AbstractUser</span></code> 提供默认 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/contrib/auth/#id1\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></code></a> 的完整实现作为 :ref:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>abstract model ` 。</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\"><span class=\"pre\">AbstractBaseUser</span></code></a> 的任何子类兼容：</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/2.1/topics/auth/default/#django.contrib.auth.forms.AuthenticationForm\" title=\"django.contrib.auth.forms.AuthenticationForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">AuthenticationForm</span></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\"><span class=\"pre\">USERNAME_FIELD</span></code></a> 指定的username字段。</p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/2.1/topics/auth/default/#django.contrib.auth.forms.SetPasswordForm\" title=\"django.contrib.auth.forms.SetPasswordForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">SetPasswordForm</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/2.1/topics/auth/default/#django.contrib.auth.forms.PasswordChangeForm\" title=\"django.contrib.auth.forms.PasswordChangeForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">PasswordChangeForm</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/2.1/topics/auth/default/#django.contrib.auth.forms.AdminPasswordChangeForm\" title=\"django.contrib.auth.forms.AdminPasswordChangeForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">AdminPasswordChangeForm</span></code></a></p></li>\n</ul>\n<p>以下表单对用户模型进行了假设，如果满足这些假设，则可以按原样使用:</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/2.1/topics/auth/default/#django.contrib.auth.forms.PasswordResetForm\" title=\"django.contrib.auth.forms.PasswordResetForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">PasswordResetForm</span></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\"><span class=\"pre\">get_email_field_name()</span></code></a> 返回（默认为电子邮件），这个方法用来标识用户，以及名为``is_active``的布尔字段，防止非活动用户重置密码。</p></li>\n</ul>\n<p>最后，下面的表单和 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/contrib/auth/#id1\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></code></a> 绑定，如果需要和自定义的用户模型一起使用，则需要重写或者扩展。</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/2.1/topics/auth/default/#django.contrib.auth.forms.UserCreationForm\" title=\"django.contrib.auth.forms.UserCreationForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">UserCreationForm</span></code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/2.1/topics/auth/default/#django.contrib.auth.forms.UserChangeForm\" title=\"django.contrib.auth.forms.UserChangeForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">UserChangeForm</span></code></a></p></li>\n</ul>\n<p>如果自定义的用户模型是 <code class=\"docutils literal notranslate\"><span class=\"pre\">AbstractUser</span></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=\"w\"> </span><span class=\"nn\">django.contrib.auth.forms</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">UserCreationForm</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">myapp.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">CustomUser</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">CustomUserCreationForm</span><span class=\"p\">(</span><span class=\"n\">UserCreationForm</span><span class=\"p\">):</span>\n\n    <span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Meta</span><span class=\"p\">(</span><span class=\"n\">UserCreationForm</span><span class=\"o\">.</span><span class=\"n\">Meta</span><span class=\"p\">):</span>\n        <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">CustomUser</span>\n        <span class=\"n\">fields</span> <span class=\"o\">=</span> <span class=\"n\">UserCreationForm</span><span class=\"o\">.</span><span class=\"n\">Meta</span><span class=\"o\">.</span><span class=\"n\">fields</span> <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/2.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\"><span class=\"pre\">django.contrib.admin</span></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\" id=\"id0\">\n<em class=\"property\"><span class=\"k\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">models.</span></span><span class=\"sig-name descname\"><span class=\"pre\">CustomUser</span></span><a class=\"heading-anchor\" href=\"#id0\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></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\"><span class=\"pre\">is_staff</span></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\"><span class=\"pre\">True</span></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\"><span class=\"pre\">is_active</span></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\"><span class=\"pre\">has_perm(perm,</span> <span class=\"pre\">obj=None):</span></span></dt>\n<dd><p>如果用户有指定的权限，则返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> 。如果提供了参数 <code class=\"docutils literal notranslate\"><span class=\"pre\">obj</span></code>  ，则需要对指定的对象实例进行权限检查。</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\">\n<span class=\"sig-name descname\"><span class=\"pre\">has_module_perms(app_label):</span></span></dt>\n<dd><p>如果用户有权限访问指定 app 里的模型，那么返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> 。</p>\n</dd></dl>\n\n<p>你也需要在 admin 文件里注册自定义的用户模型。如果自定义的用户模型扩展了  <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.models.AbstractUser</span></code> ，你可以直接使用Django已有的类 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.admin.UserAdmin</span></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\"><span class=\"pre\">AbstractBaseUser</span></code></a> ，你将需要定义一个自定义的类 <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code> 。不管怎样，你都将需要重写任何引用 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.auth.models.AbstractUser</span></code> 上的字段的定义，这些字段不在你自定义的用户类中。</p>\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\"><span class=\"pre\">PermissionsMixin</span></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\"><span class=\"pre\">PermissionsMixin</span></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\"><span class=\"pre\">class</span></span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">models.</span></span><span class=\"sig-name descname\"><span class=\"pre\">PermissionsMixin</span></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\"><span class=\"pre\">is_superuser</span></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_group_permissions\">\n<span class=\"sig-name descname\"><span class=\"pre\">get_group_permissions</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">obj</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></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\"><span class=\"pre\">obj</span></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\"><span class=\"pre\">get_all_permissions</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">obj</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></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\"><span class=\"pre\">has_perm</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">perm</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">obj</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></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\"><span class=\"pre\">True</span></code> ，其中 <code class=\"docutils literal notranslate\"><span class=\"pre\">perm</span></code> 的格式为 <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;&lt;app</span> <span class=\"pre\">label&gt;.&lt;permission</span> <span class=\"pre\">codename&gt;&quot;</span></code> (see <a class=\"reference internal\" href=\"/zh-hans/2.1/topics/auth/default/#topic-authorization\"><span class=\"std std-ref\">permissions</span></a>)。如果 <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">User.is_active</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">is_superuser</span></code></a> 都为 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>，则这个方法一直返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> 。</p>\n<p>如果传入 <code class=\"docutils literal notranslate\"><span class=\"pre\">obj</span></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\"><span class=\"pre\">has_perms</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">perm_list</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">obj</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></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\"><span class=\"pre\">True</span></code> ，其中perm的格式为 <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;&lt;app</span> <span class=\"pre\">label&gt;.&lt;permission</span> <span class=\"pre\">codename&gt;&quot;</span></code> 。如果 <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">User.is_active</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">is_superuser</span></code></a> 都返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> ，则这个方法一直返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> 。</p>\n<p>如果传入参数  <code class=\"docutils literal notranslate\"><span class=\"pre\">obj</span></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\"><span class=\"pre\">has_module_perms</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">package_name</span></span></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\"><span class=\"pre\">True</span></code> 。如果 <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">User.is_active</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/2.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\"><span class=\"pre\">is_superuser</span></code></a> 都为 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> ，则该方法一直返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> 。</p>\n</dd></dl>\n\n</dd></dl>\n\n<aside class=\"admonition-permissionsmixin-and-modelbackend admonition\">\n<p class=\"admonition-title\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PermissionsMixin</span></code>  和  <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelBackend</span></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\"><span class=\"pre\">PermissionsMixin</span></code></a> ，必须确保没有调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelBackend</span></code> 的权限方法。<code class=\"docutils literal notranslate\"><span class=\"pre\">ModelBackend</span></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/2.1/ref/contrib/auth/#id1\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></code></a> 的代理模型。代理模型必须基于具体的基类；通过定义自定义用户模型，你就移除了Django可靠地识别基类的功能。</p>\n<p>如果你的项目正在使用代理模型，你必须修改扩展用户模型的代理，或者把代理的行为都合并到 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/contrib/auth/#id1\" title=\"django.contrib.auth.models.User\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">User</span></code></a> 子类里去。</p>\n</section>\n<section id=\"a-full-example\">\n<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\"><span class=\"pre\">admin</span></code>  flag 来对用户账户进行权限检查。除了用户创建的表单外，此模型和所有内置的身份验证表单和视图兼容。此例只是说明了大多数组件如何协同工作，不要直接复制到生产环境里。</p>\n<p>这段代码将一直存在于 <code class=\"docutils literal notranslate\"><span class=\"pre\">models.py</span></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=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">models</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"p\">(</span>\n    <span class=\"n\">BaseUserManager</span><span class=\"p\">,</span> <span class=\"n\">AbstractBaseUser</span>\n<span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MyUserManager</span><span class=\"p\">(</span><span class=\"n\">BaseUserManager</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">create_user</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">email</span><span class=\"p\">,</span> <span class=\"n\">date_of_birth</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><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> <span class=\"n\">email</span><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        <span class=\"n\">user</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">model</span><span class=\"p\">(</span>\n            <span class=\"n\">email</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">normalize_email</span><span class=\"p\">(</span><span class=\"n\">email</span><span class=\"p\">),</span>\n            <span class=\"n\">date_of_birth</span><span class=\"o\">=</span><span class=\"n\">date_of_birth</span><span class=\"p\">,</span>\n        <span class=\"p\">)</span>\n\n        <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">set_password</span><span class=\"p\">(</span><span class=\"n\">password</span><span class=\"p\">)</span>\n        <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">using</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_db</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">user</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">create_superuser</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">email</span><span class=\"p\">,</span> <span class=\"n\">date_of_birth</span><span class=\"p\">,</span> <span class=\"n\">password</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><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        <span class=\"n\">user</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">create_user</span><span class=\"p\">(</span>\n            <span class=\"n\">email</span><span class=\"p\">,</span>\n            <span class=\"n\">password</span><span class=\"o\">=</span><span class=\"n\">password</span><span class=\"p\">,</span>\n            <span class=\"n\">date_of_birth</span><span class=\"o\">=</span><span class=\"n\">date_of_birth</span><span class=\"p\">,</span>\n        <span class=\"p\">)</span>\n        <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">is_admin</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n        <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">using</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_db</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">user</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MyUser</span><span class=\"p\">(</span><span class=\"n\">AbstractBaseUser</span><span class=\"p\">):</span>\n    <span class=\"n\">email</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">EmailField</span><span class=\"p\">(</span>\n        <span class=\"n\">verbose_name</span><span class=\"o\">=</span><span class=\"s1\">&#39;email address&#39;</span><span class=\"p\">,</span>\n        <span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">255</span><span class=\"p\">,</span>\n        <span class=\"n\">unique</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n    <span class=\"n\">date_of_birth</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">DateField</span><span class=\"p\">()</span>\n    <span class=\"n\">is_active</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">BooleanField</span><span class=\"p\">(</span><span class=\"n\">default</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n    <span class=\"n\">is_admin</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">BooleanField</span><span class=\"p\">(</span><span class=\"n\">default</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n\n    <span class=\"n\">objects</span> <span class=\"o\">=</span> <span class=\"n\">MyUserManager</span><span class=\"p\">()</span>\n\n    <span class=\"n\">USERNAME_FIELD</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;email&#39;</span>\n    <span class=\"n\">REQUIRED_FIELDS</span> <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=\"w\"> </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><span class=\"n\">email</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">has_perm</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">perm</span><span class=\"p\">,</span> <span class=\"n\">obj</span><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=\"w\"> </span><span class=\"nf\">has_module_perms</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">app_label</span><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=\"w\"> </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><span class=\"n\">is_admin</span>\n</code></pre></div>\n<p>然后，在 Django 管理后台里注册这个用户模型，下面这些代码必须在 app 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">admin.py</span></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=\"w\"> </span><span class=\"nn\">django</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">forms</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">admin</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Group</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.admin</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">UserAdmin</span> <span class=\"k\">as</span> <span class=\"n\">BaseUserAdmin</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.forms</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">ReadOnlyPasswordHashField</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">customauth.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">MyUser</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">UserCreationForm</span><span class=\"p\">(</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">ModelForm</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><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    <span class=\"n\">password1</span> <span class=\"o\">=</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">label</span><span class=\"o\">=</span><span class=\"s1\">&#39;Password&#39;</span><span class=\"p\">,</span> <span class=\"n\">widget</span><span class=\"o\">=</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">PasswordInput</span><span class=\"p\">)</span>\n    <span class=\"n\">password2</span> <span class=\"o\">=</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">label</span><span class=\"o\">=</span><span class=\"s1\">&#39;Password confirmation&#39;</span><span class=\"p\">,</span> <span class=\"n\">widget</span><span class=\"o\">=</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">PasswordInput</span><span class=\"p\">)</span>\n\n    <span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">MyUser</span>\n        <span class=\"n\">fields</span> <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=\"w\"> </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        <span class=\"n\">password1</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">cleaned_data</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">&quot;password1&quot;</span><span class=\"p\">)</span>\n        <span class=\"n\">password2</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">cleaned_data</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">&quot;password2&quot;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">password1</span> <span class=\"ow\">and</span> <span class=\"n\">password2</span> <span class=\"ow\">and</span> <span class=\"n\">password1</span> <span class=\"o\">!=</span> <span class=\"n\">password2</span><span class=\"p\">:</span>\n            <span class=\"k\">raise</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">ValidationError</span><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> <span class=\"n\">password2</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">save</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">commit</span><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        <span class=\"n\">user</span> <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">(</span><span class=\"n\">commit</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n        <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">set_password</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">cleaned_data</span><span class=\"p\">[</span><span class=\"s2\">&quot;password1&quot;</span><span class=\"p\">])</span>\n        <span class=\"k\">if</span> <span class=\"n\">commit</span><span class=\"p\">:</span>\n            <span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">user</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">UserChangeForm</span><span class=\"p\">(</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">ModelForm</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><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\">    password hash display field.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">password</span> <span class=\"o\">=</span> <span class=\"n\">ReadOnlyPasswordHashField</span><span class=\"p\">()</span>\n\n    <span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Meta</span><span class=\"p\">:</span>\n        <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">MyUser</span>\n        <span class=\"n\">fields</span> <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    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">clean_password</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Regardless of what the user provides, return the initial value.</span>\n        <span class=\"c1\"># This is done here, rather than on the field, because the</span>\n        <span class=\"c1\"># field does not have access to the initial value</span>\n        <span class=\"k\">return</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">initial</span><span class=\"p\">[</span><span class=\"s2\">&quot;password&quot;</span><span class=\"p\">]</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">UserAdmin</span><span class=\"p\">(</span><span class=\"n\">BaseUserAdmin</span><span class=\"p\">):</span>\n    <span class=\"c1\"># The forms to add and change user instances</span>\n    <span class=\"n\">form</span> <span class=\"o\">=</span> <span class=\"n\">UserChangeForm</span>\n    <span class=\"n\">add_form</span> <span class=\"o\">=</span> <span class=\"n\">UserCreationForm</span>\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    <span class=\"n\">list_display</span> <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    <span class=\"n\">list_filter</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;is_admin&#39;</span><span class=\"p\">,)</span>\n    <span class=\"n\">fieldsets</span> <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    <span class=\"n\">add_fieldsets</span> <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    <span class=\"n\">search_fields</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;email&#39;</span><span class=\"p\">,)</span>\n    <span class=\"n\">ordering</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;email&#39;</span><span class=\"p\">,)</span>\n    <span class=\"n\">filter_horizontal</span> <span class=\"o\">=</span> <span class=\"p\">()</span>\n\n<span class=\"c1\"># Now register the new UserAdmin...</span>\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">MyUser</span><span class=\"p\">,</span> <span class=\"n\">UserAdmin</span><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>\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">unregister</span><span class=\"p\">(</span><span class=\"n\">Group</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>最后，在项目配置文件中的 <a class=\"reference internal\" href=\"/zh-hans/2.1/ref/settings/#std-setting-AUTH_USER_MODEL\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">AUTH_USER_MODEL</span></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=\"n\">AUTH_USER_MODEL</span> <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":"Using Django","url":"/zh-hans/2.1/topics/"},{"docname":"topics/auth/index","title":"Django中的用户认证","url":"/zh-hans/2.1/topics/auth/"}],"prev":{"docname":"topics/auth/passwords","title":"Django中的密码管理","url":"/zh-hans/2.1/topics/auth/passwords/"},"next":{"docname":"topics/cache","title":"Django's cache framework","url":"/zh-hans/2.1/topics/cache/"},"formats":{"html":"/zh-hans/2.1/topics/auth/customizing/","markdown":"/zh-hans/2.1/topics/auth/customizing.md","json":"/zh-hans/2.1/topics/auth/customizing.json"},"source":"https://github.com/django/django/blob/stable/2.1.x/docs/topics/auth/customizing.txt","official":"https://docs.djangoproject.com/zh-hans/2.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","pt-br","ko","es","el","pl"]}