{"title":"管理动作","version":"4.1","locale":"zh-hans","docname":"ref/contrib/admin/actions","url":"/zh-hans/4.1/ref/contrib/admin/actions/","canonical":"https://djangodocs.dev/zh-hans/4.1/ref/contrib/admin/actions/","summary":"Django 的管理员的基本工作流程，简而言之，就是“选择一个对象，然后更改它”。这对于大多数用例来说都很好用。然而，如果你需要同时对许多对象进行相同的更改，这种工作流程可能会相当乏味。 在这种情况下，Django 的管理可以让你编写和注册“动作”——即使用在变更列表页面上选择的对象列表调用的函数。…","html":"<h1>管理动作<a class=\"heading-anchor\" href=\"#admin-actions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django 的管理员的基本工作流程，简而言之，就是“选择一个对象，然后更改它”。这对于大多数用例来说都很好用。然而，如果你需要同时对许多对象进行相同的更改，这种工作流程可能会相当乏味。</p>\n<p>在这种情况下，Django 的管理可以让你编写和注册“动作”——即使用在变更列表页面上选择的对象列表调用的函数。</p>\n<p>如果你在管理中查看任何变化列表，你会看到这个功能的作用；Django 自带了一个“删除选定对象”的动作，所有模型都可以使用。例如，这里是 Django 内置的用户模块 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/auth/#module-django.contrib.auth\" title=\"django.contrib.auth: Django's authentication framework.\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">django.contrib.auth</span></code></a> 应用：</p>\n<img alt=\"/zh-hans/4.1/_images/admin-actions.png\" src=\"/zh-hans/4.1/_images/admin-actions.png\" />\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>“删除选定对象”动作使用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/querysets/#django.db.models.query.QuerySet.delete\" title=\"django.db.models.query.QuerySet.delete\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">QuerySet.delete()</span></code></a> 为了提高效率，它有一个重要的注意事项：你的模型的 <code class=\"docutils literal notranslate\"><span class=\"pre\">delete()</span></code> 方法将不会被调用。</p>\n<p>如果你想覆盖这个行为，你可以覆盖 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.delete_queryset\" title=\"django.contrib.admin.ModelAdmin.delete_queryset\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">ModelAdmin.delete_queryset()</span></code></a> 或者写一个自定义的动作，以你喜欢的方式进行删除 -- 例如，通过为每个选定的项目调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">Model.delete()</span></code>。</p>\n<p>关于批量删除的更多背景，请参见 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/db/queries/#topics-db-queries-delete\"><span class=\"std std-ref\">对象删除</span></a> 的文档。</p>\n</aside>\n<p>请继续阅读，了解如何将自己的动作添加到此列表中。</p>\n<section id=\"writing-actions\">\n<h2>编写动作<a class=\"heading-anchor\" href=\"#writing-actions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>解释动作的最简单的方法就是举例说明，所以让我们潜心研究。</p>\n<p>管理动作的一个常见用例是模型的批量更新。想象一下，一个新闻应用程序有一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">Article</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.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">models</span>\n\n<span class=\"n\">STATUS_CHOICES</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"p\">(</span><span class=\"s1\">&#39;d&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Draft&#39;</span><span class=\"p\">),</span>\n    <span class=\"p\">(</span><span class=\"s1\">&#39;p&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Published&#39;</span><span class=\"p\">),</span>\n    <span class=\"p\">(</span><span class=\"s1\">&#39;w&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Withdrawn&#39;</span><span class=\"p\">),</span>\n<span class=\"p\">]</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\">title</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    <span class=\"n\">body</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">TextField</span><span class=\"p\">()</span>\n    <span class=\"n\">status</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\">1</span><span class=\"p\">,</span> <span class=\"n\">choices</span><span class=\"o\">=</span><span class=\"n\">STATUS_CHOICES</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\">title</span>\n</code></pre></div>\n<p>我们可能会用这样的模型来执行一个常见的任务，就是将一篇文章的状态从 “草稿” 更新为 “已发布”。我们可以很容易地在管理员中一次只发布一篇文章，但如果我们想批量发布一组文章，就会很繁琐。所以，让我们编写一个动作，让我们可以把一篇文章的状态改为 “已发布”。</p>\n<section id=\"writing-action-functions\">\n<h3>编写动作函数<a class=\"heading-anchor\" href=\"#writing-action-functions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>首先，我们需要写一个函数，当管理触发动作时就会被调用。动作函数是常规函数，它有三个参数：</p>\n<ul class=\"simple\">\n<li><p>当前 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code></a></p></li>\n<li><p>一个代表当前请求的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a>，</p></li>\n<li><p>一个包含用户所选择的对象集合的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/querysets/#django.db.models.query.QuerySet\" title=\"django.db.models.query.QuerySet\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code></a>。</p></li>\n</ul>\n<p>我们的 publish-these-articles 函数不需要 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelAdmin</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=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_published</span><span class=\"p\">(</span><span class=\"n\">modeladmin</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">queryset</span><span class=\"p\">):</span>\n    <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">status</span><span class=\"o\">=</span><span class=\"s1\">&#39;p&#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>为了获得最佳性能，我们使用查询集的 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/db/queries/#topics-db-queries-update\"><span class=\"std std-ref\">update 方法</span></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=\"k\">for</span> <span class=\"n\">obj</span> <span class=\"ow\">in</span> <span class=\"n\">queryset</span><span class=\"p\">:</span>\n    <span class=\"n\">do_something_with</span><span class=\"p\">(</span><span class=\"n\">obj</span><span class=\"p\">)</span>\n</code></pre></div>\n</aside>\n<p>其实这就是写一个动作的全部内容了！然而，我们将再采取一个可选的但很有用的步骤，在管理中给这个动作一个 “漂亮” 的标题。默认情况下，这个操作会在操作列表中显示为 “Make published” —— 函数名称，下划线用空格代替。这很好，但我们可以通过在 <code class=\"docutils literal notranslate\"><span class=\"pre\">make_published</span></code> 函数上使用 <a class=\"reference internal\" href=\"#django.contrib.admin.action\" title=\"django.contrib.admin.action\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">action()</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.contrib</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">admin</span>\n\n<span class=\"o\">...</span>\n\n<span class=\"nd\">@admin</span><span class=\"o\">.</span><span class=\"n\">action</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s1\">&#39;Mark selected stories as published&#39;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_published</span><span class=\"p\">(</span><span class=\"n\">modeladmin</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">queryset</span><span class=\"p\">):</span>\n    <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">status</span><span class=\"o\">=</span><span class=\"s1\">&#39;p&#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>这可能看起来很熟悉；管理的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display\" title=\"django.contrib.admin.ModelAdmin.list_display\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">list_display</span></code></a> 选项与 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.display\" title=\"django.contrib.admin.display\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">display()</span></code></a> 装饰器使用了类似的技术，也为在那里注册的回调函数提供了人类可读的描述。</p>\n</aside>\n</section>\n<section id=\"adding-actions-to-the-modeladmin\">\n<h3>在 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code></a> 中添加动作<a class=\"heading-anchor\" href=\"#adding-actions-to-the-modeladmin\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>接下来，我们需要通知我们的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code></a> 的动作。这就像其他配置选项一样。因此，完整的 <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\">myapp.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Article</span>\n\n<span class=\"nd\">@admin</span><span class=\"o\">.</span><span class=\"n\">action</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s1\">&#39;Mark selected stories as published&#39;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_published</span><span class=\"p\">(</span><span class=\"n\">modeladmin</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">queryset</span><span class=\"p\">):</span>\n    <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">status</span><span class=\"o\">=</span><span class=\"s1\">&#39;p&#39;</span><span class=\"p\">)</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ArticleAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"n\">list_display</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;title&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;status&#39;</span><span class=\"p\">]</span>\n    <span class=\"n\">ordering</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;title&#39;</span><span class=\"p\">]</span>\n    <span class=\"n\">actions</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">make_published</span><span class=\"p\">]</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\">Article</span><span class=\"p\">,</span> <span class=\"n\">ArticleAdmin</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这段代码会给我们一个管理变更列表，看起来像这样：</p>\n<img alt=\"/zh-hans/4.1/_images/adding-actions-to-the-modeladmin.png\" src=\"/zh-hans/4.1/_images/adding-actions-to-the-modeladmin.png\" />\n<p>这其实就是全部的内容了！如果你渴望编写自己的动作，你现在已经知道了足够的知识，可以开始了。本文档的其余部分涵盖了更多的高级技术。</p>\n</section>\n<section id=\"handling-errors-in-actions\">\n<h3>处理动作中的错误<a class=\"heading-anchor\" href=\"#handling-errors-in-actions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果在运行你的动作时可能出现可预见的错误情况，你应该优雅地告知用户问题。这意味着处理异常，并使用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.message_user\" title=\"django.contrib.admin.ModelAdmin.message_user\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">django.contrib.admin.ModelAdmin.message_user()</span></code></a> 在响应中显示一个用户友好的问题描述。</p>\n</section>\n</section>\n<section id=\"advanced-action-techniques\">\n<h2>进阶动作技巧<a class=\"heading-anchor\" href=\"#advanced-action-techniques\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>有几个额外的选项和可能性，你可以利用它们实现更高级的选项。</p>\n<section id=\"actions-as-modeladmin-methods\">\n<h3>作为 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code></a> 方法的动作<a class=\"heading-anchor\" href=\"#actions-as-modeladmin-methods\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>上面的例子显示了 <code class=\"docutils literal notranslate\"><span class=\"pre\">make_published</span></code> 动作被定义为一个函数。这很好，但从代码设计的角度来看并不完美：由于该动作与 <code class=\"docutils literal notranslate\"><span class=\"pre\">Article</span></code> 对象紧密耦合，因此将该动作挂到 <code class=\"docutils literal notranslate\"><span class=\"pre\">ArticleAdmin</span></code> 对象本身是合理的。</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\">ArticleAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n\n    <span class=\"n\">actions</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;make_published&#39;</span><span class=\"p\">]</span>\n\n    <span class=\"nd\">@admin</span><span class=\"o\">.</span><span class=\"n\">action</span><span class=\"p\">(</span><span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s1\">&#39;Mark selected stories as published&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_published</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\">queryset</span><span class=\"p\">):</span>\n        <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">status</span><span class=\"o\">=</span><span class=\"s1\">&#39;p&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>请注意，首先我们把 <code class=\"docutils literal notranslate\"><span class=\"pre\">make_published</span></code> 移到了一个方法中，并把 <code class=\"docutils literal notranslate\"><span class=\"pre\">modeladmin</span></code> 参数重命名为 <code class=\"docutils literal notranslate\"><span class=\"pre\">self</span></code>，其次我们现在把字符串 <code class=\"docutils literal notranslate\"><span class=\"pre\">'make_published'</span></code> 放在了 <code class=\"docutils literal notranslate\"><span class=\"pre\">actions</span></code> 中，而不是直接的函数引用。这就告诉 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code></a> 把动作作为方法来查找。</p>\n<p>将动作定义为方法，让动作对 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code></a> 本身有更多的习惯用法，允许动作调用管理提供的任何方法。</p>\n<p id=\"custom-admin-action\">例如，我们可以使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">self</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\">messages</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.utils.translation</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">ngettext</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ArticleAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_published</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\">queryset</span><span class=\"p\">):</span>\n        <span class=\"n\">updated</span> <span class=\"o\">=</span> <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">status</span><span class=\"o\">=</span><span class=\"s1\">&#39;p&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">message_user</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">ngettext</span><span class=\"p\">(</span>\n            <span class=\"s1\">&#39;</span><span class=\"si\">%d</span><span class=\"s1\"> story was successfully marked as published.&#39;</span><span class=\"p\">,</span>\n            <span class=\"s1\">&#39;</span><span class=\"si\">%d</span><span class=\"s1\"> stories were successfully marked as published.&#39;</span><span class=\"p\">,</span>\n            <span class=\"n\">updated</span><span class=\"p\">,</span>\n        <span class=\"p\">)</span> <span class=\"o\">%</span> <span class=\"n\">updated</span><span class=\"p\">,</span> <span class=\"n\">messages</span><span class=\"o\">.</span><span class=\"n\">SUCCESS</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这就使得在成功执行一个动作后，该动作与管理本身所做的动作相匹配。</p>\n<img alt=\"/zh-hans/4.1/_images/actions-as-modeladmin-methods.png\" src=\"/zh-hans/4.1/_images/actions-as-modeladmin-methods.png\" />\n</section>\n<section id=\"actions-that-provide-intermediate-pages\">\n<h3>提供中间页的动作<a class=\"heading-anchor\" href=\"#actions-that-provide-intermediate-pages\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>默认情况下，在执行完一个操作后，用户会被重定向回原来的变更列表页面。但是，有些操作，尤其是比较复杂的操作，需要返回中间页面。例如，内置的删除操作在删除所选对象之前会要求确认。</p>\n<p>要提供一个中间页，从你的操作中返回一个 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> （或子类）。例如，你可以写一个导出函数，使用 Django 的 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/serialization/\"><span class=\"doc\">序列化函数</span></a> 将一些选定的对象转储为 JSON：</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.core</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">serializers</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponse</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">export_as_json</span><span class=\"p\">(</span><span class=\"n\">modeladmin</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">queryset</span><span class=\"p\">):</span>\n    <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">HttpResponse</span><span class=\"p\">(</span><span class=\"n\">content_type</span><span class=\"o\">=</span><span class=\"s2\">&quot;application/json&quot;</span><span class=\"p\">)</span>\n    <span class=\"n\">serializers</span><span class=\"o\">.</span><span class=\"n\">serialize</span><span class=\"p\">(</span><span class=\"s2\">&quot;json&quot;</span><span class=\"p\">,</span> <span class=\"n\">queryset</span><span class=\"p\">,</span> <span class=\"n\">stream</span><span class=\"o\">=</span><span class=\"n\">response</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">response</span>\n</code></pre></div>\n<p>一般来说，像上面这样的东西并不被认为是一个好主意。大多数时候，最好的做法是返回一个 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseRedirect</span></code></a>，并将用户重定向到你编写的视图，在 GET 查询字符串中传递所选对象的列表。这样你就可以在中间页面上提供复杂的交互逻辑。例如，如果你想提供一个更完整的导出功能，你会想让用户选择一种格式，也可能是一个要包含在导出中的字段列表。最好的办法是写一个小的动作，重定向到你的自定义导出视图：</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.contenttypes.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">ContentType</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponseRedirect</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">export_selected_objects</span><span class=\"p\">(</span><span class=\"n\">modeladmin</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">queryset</span><span class=\"p\">):</span>\n    <span class=\"n\">selected</span> <span class=\"o\">=</span> <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">values_list</span><span class=\"p\">(</span><span class=\"s1\">&#39;pk&#39;</span><span class=\"p\">,</span> <span class=\"n\">flat</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n    <span class=\"n\">ct</span> <span class=\"o\">=</span> <span class=\"n\">ContentType</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get_for_model</span><span class=\"p\">(</span><span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">model</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">HttpResponseRedirect</span><span class=\"p\">(</span><span class=\"s1\">&#39;/export/?ct=</span><span class=\"si\">%s</span><span class=\"s1\">&amp;ids=</span><span class=\"si\">%s</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"p\">(</span>\n        <span class=\"n\">ct</span><span class=\"o\">.</span><span class=\"n\">pk</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;,&#39;</span><span class=\"o\">.</span><span class=\"n\">join</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">pk</span><span class=\"p\">)</span> <span class=\"k\">for</span> <span class=\"n\">pk</span> <span class=\"ow\">in</span> <span class=\"n\">selected</span><span class=\"p\">),</span>\n    <span class=\"p\">))</span>\n</code></pre></div>\n<p>正如你所看到的，这个动作相当简短；所有复杂的逻辑都属于你的导出视图。这将需要处理任何类型的对象，因此有 <code class=\"docutils literal notranslate\"><span class=\"pre\">ContentType</span></code> 的业务。</p>\n<p>如何编写这个视图，就留给读者去练习。</p>\n</section>\n<section id=\"making-actions-available-site-wide\">\n<span id=\"adminsite-actions\"></span><h3>在整个站点提供动作<a class=\"heading-anchor\" href=\"#making-actions-available-site-wide\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.admin.AdminSite.add_action\">\n<span class=\"sig-prename descclassname\"><span class=\"pre\">AdminSite.</span></span><span class=\"sig-name descname\"><span class=\"pre\">add_action</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">action</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">name</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.admin.AdminSite.add_action\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>有些动作最好是对管理员站点中的 <em>任何</em> 对象开放 —— 上面定义的导出动作就是一个很好的选择。你可以使用 <a class=\"reference internal\" href=\"#django.contrib.admin.AdminSite.add_action\" title=\"django.contrib.admin.AdminSite.add_action\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">AdminSite.add_action()</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.contrib</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">admin</span>\n\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">add_action</span><span class=\"p\">(</span><span class=\"n\">export_selected_objects</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这使得 <code class=\"docutils literal notranslate\"><span class=\"pre\">export_selected_objects</span></code> 动作作为一个名为 “export_selected_objects” 的动作在全站范围内可用。你可以通过向 <a class=\"reference internal\" href=\"#django.contrib.admin.AdminSite.add_action\" title=\"django.contrib.admin.AdminSite.add_action\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">AdminSite.add_action()</span></code></a> 传递第二个参数，来明确地给这个动作起一个名字 —— 如果你以后想以编程方式 <a class=\"reference internal\" href=\"#disabling-admin-actions\"><span class=\"std std-ref\">移除此动作</span></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\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">add_action</span><span class=\"p\">(</span><span class=\"n\">export_selected_objects</span><span class=\"p\">,</span> <span class=\"s1\">&#39;export_selected&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n</dd></dl>\n\n</section>\n<section id=\"disabling-actions\">\n<span id=\"disabling-admin-actions\"></span><h3>禁用动作<a class=\"heading-anchor\" href=\"#disabling-actions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>有时你需要针对特定对象禁用某些动作 —— 特别是那些 <a class=\"reference internal\" href=\"#adminsite-actions\"><span class=\"std std-ref\">全站点注册的</span></a>。有几种方法可以禁用动作：</p>\n<section id=\"disabling-a-site-wide-action\">\n<h4>禁用全站点动作<a class=\"heading-anchor\" href=\"#disabling-a-site-wide-action\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.admin.AdminSite.disable_action\">\n<span class=\"sig-prename descclassname\"><span class=\"pre\">AdminSite.</span></span><span class=\"sig-name descname\"><span class=\"pre\">disable_action</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">name</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.admin.AdminSite.disable_action\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>如果你需要禁用一个 <a class=\"reference internal\" href=\"#adminsite-actions\"><span class=\"std std-ref\">全站点动作</span></a> 你可以调用 <a class=\"reference internal\" href=\"#django.contrib.admin.AdminSite.disable_action\" title=\"django.contrib.admin.AdminSite.disable_action\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">AdminSite.disable_action()</span></code></a>。</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=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">disable_action</span><span class=\"p\">(</span><span class=\"s1\">&#39;delete_selected&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>一旦你完成了上述操作，该动作将不再在全站范围内使用。</p>\n<p>If, however, you need to reenable a globally-disabled action for one\nparticular model, list it explicitly in your <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelAdmin.actions</span></code> list:</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=\"c1\"># Globally disable delete selected</span>\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">disable_action</span><span class=\"p\">(</span><span class=\"s1\">&#39;delete_selected&#39;</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># This ModelAdmin will not have delete_selected available</span>\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">SomeModelAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"n\">actions</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;some_other_action&#39;</span><span class=\"p\">]</span>\n    <span class=\"o\">...</span>\n\n<span class=\"c1\"># This one will</span>\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AnotherModelAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"n\">actions</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;delete_selected&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;a_third_action&#39;</span><span class=\"p\">]</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n</dd></dl>\n\n</section>\n<section id=\"disabling-all-actions-for-a-particular-modeladmin\">\n<h4>禁用特定 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code></a> 的所有动作<a class=\"heading-anchor\" href=\"#disabling-all-actions-for-a-particular-modeladmin\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>如果你想让给定的 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code></a> <em>没有</em> 批量操作，请将 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.actions\" title=\"django.contrib.admin.ModelAdmin.actions\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">ModelAdmin.actions</span></code></a> 设置为 <code class=\"docutils literal notranslate\"><span class=\"pre\">None</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\">MyModelAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"n\">actions</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n</code></pre></div>\n<p>这告诉 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin\" title=\"django.contrib.admin.ModelAdmin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code></a> 不显示或允许任何操作，包括任何 <a class=\"reference internal\" href=\"#adminsite-actions\"><span class=\"std std-ref\">全站点动作</span></a>。</p>\n</section>\n<section id=\"conditionally-enabling-or-disabling-actions\">\n<h4>有条件地启用或禁用动作<a class=\"heading-anchor\" href=\"#conditionally-enabling-or-disabling-actions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.admin.ModelAdmin.get_actions\">\n<span class=\"sig-prename descclassname\"><span class=\"pre\">ModelAdmin.</span></span><span class=\"sig-name descname\"><span class=\"pre\">get_actions</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">request</span></span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.contrib.admin.ModelAdmin.get_actions\"><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.admin.ModelAdmin.get_actions\" title=\"django.contrib.admin.ModelAdmin.get_actions\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">ModelAdmin.get_actions()</span></code></a> 来有条件地启用或禁用每个请求（也就是每个用户）的动作。</p>\n<p>这将返回一个允许动作的字典。键是动作名称，值是 <code class=\"docutils literal notranslate\"><span class=\"pre\">(function,</span> <span class=\"pre\">name,</span> <span class=\"pre\">short_description)</span></code> 元组。</p>\n<p>例如，如果你只想让名字以 “J” 开头的用户能够批量删除对象：</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\">MyModelAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_actions</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">):</span>\n        <span class=\"n\">actions</span> <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">get_actions</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">username</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">upper</span><span class=\"p\">()</span> <span class=\"o\">!=</span> <span class=\"s1\">&#39;J&#39;</span><span class=\"p\">:</span>\n            <span class=\"k\">if</span> <span class=\"s1\">&#39;delete_selected&#39;</span> <span class=\"ow\">in</span> <span class=\"n\">actions</span><span class=\"p\">:</span>\n                <span class=\"k\">del</span> <span class=\"n\">actions</span><span class=\"p\">[</span><span class=\"s1\">&#39;delete_selected&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">return</span> <span class=\"n\">actions</span>\n</code></pre></div>\n</dd></dl>\n\n</section>\n</section>\n<section id=\"setting-permissions-for-actions\">\n<span id=\"admin-action-permissions\"></span><h3>设置动作的权限<a class=\"heading-anchor\" href=\"#setting-permissions-for-actions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>通过使用 <a class=\"reference internal\" href=\"#django.contrib.admin.action\" title=\"django.contrib.admin.action\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">action()</span></code></a> 装饰器包装动作函数，并传递 <code class=\"docutils literal notranslate\"><span class=\"pre\">permissions</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=\"nd\">@admin</span><span class=\"o\">.</span><span class=\"n\">action</span><span class=\"p\">(</span><span class=\"n\">permissions</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;change&#39;</span><span class=\"p\">])</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_published</span><span class=\"p\">(</span><span class=\"n\">modeladmin</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">queryset</span><span class=\"p\">):</span>\n    <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">status</span><span class=\"o\">=</span><span class=\"s1\">&#39;p&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">make_published()</span></code> 行动将只提供给通过 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.has_change_permission\" title=\"django.contrib.admin.ModelAdmin.has_change_permission\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">ModelAdmin.has_change_permission()</span></code></a> 检查的用户。</p>\n<p>如果 <code class=\"docutils literal notranslate\"><span class=\"pre\">permissions</span></code> 有一个以上的权限，只要用户至少通过了一项检查，该操作就可以使用。</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">permissions</span></code> 和相应的方法检查的可用值是：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'add'</span></code>: <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.has_add_permission\" title=\"django.contrib.admin.ModelAdmin.has_add_permission\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">ModelAdmin.has_add_permission()</span></code></a></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'change'</span></code>: <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.has_change_permission\" title=\"django.contrib.admin.ModelAdmin.has_change_permission\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">ModelAdmin.has_change_permission()</span></code></a></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'delete'</span></code>: <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.has_delete_permission\" title=\"django.contrib.admin.ModelAdmin.has_delete_permission\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">ModelAdmin.has_delete_permission()</span></code></a></p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">'view'</span></code>: <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.has_view_permission\" title=\"django.contrib.admin.ModelAdmin.has_view_permission\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">ModelAdmin.has_view_permission()</span></code></a></p></li>\n</ul>\n<p>你可以指定任何其他的值，只要你在 <code class=\"docutils literal notranslate\"><span class=\"pre\">ModelAdmin</span></code> 上实现一个相应的 <code class=\"docutils literal notranslate\"><span class=\"pre\">has_&lt;value&gt;_permission(self,</span> <span class=\"pre\">request)</span></code> 方法。</p>\n<p>例子：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"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</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">get_permission_codename</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ArticleAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"n\">actions</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;make_published&#39;</span><span class=\"p\">]</span>\n\n    <span class=\"nd\">@admin</span><span class=\"o\">.</span><span class=\"n\">action</span><span class=\"p\">(</span><span class=\"n\">permissions</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;publish&#39;</span><span class=\"p\">])</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_published</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\">queryset</span><span class=\"p\">):</span>\n        <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">status</span><span class=\"o\">=</span><span class=\"s1\">&#39;p&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">has_publish_permission</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;Does the user have the publish permission?&quot;&quot;&quot;</span>\n        <span class=\"n\">opts</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">opts</span>\n        <span class=\"n\">codename</span> <span class=\"o\">=</span> <span class=\"n\">get_permission_codename</span><span class=\"p\">(</span><span class=\"s1\">&#39;publish&#39;</span><span class=\"p\">,</span> <span class=\"n\">opts</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">user</span><span class=\"o\">.</span><span class=\"n\">has_perm</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"si\">%s</span><span class=\"s1\">.</span><span class=\"si\">%s</span><span class=\"s1\">&#39;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">opts</span><span class=\"o\">.</span><span class=\"n\">app_label</span><span class=\"p\">,</span> <span class=\"n\">codename</span><span class=\"p\">))</span>\n</code></pre></div>\n</section>\n</section>\n<section id=\"the-action-decorator\">\n<h2><code class=\"docutils literal notranslate\"><span class=\"pre\">action</span></code> 装饰器<a class=\"heading-anchor\" href=\"#the-action-decorator\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.contrib.admin.action\">\n<span class=\"sig-name descname\"><span class=\"pre\">action</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"keyword-only-separator o\"><abbr title=\"Keyword-only parameters separator (PEP 3102)\"><span class=\"pre\">*</span></abbr></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">permissions</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">description</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.admin.action\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>这个装饰器可以用来设置自定义动作函数的特定属性，可以使用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.actions\" title=\"django.contrib.admin.ModelAdmin.actions\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">actions</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=\"nd\">@admin</span><span class=\"o\">.</span><span class=\"n\">action</span><span class=\"p\">(</span>\n    <span class=\"n\">permissions</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;publish&#39;</span><span class=\"p\">],</span>\n    <span class=\"n\">description</span><span class=\"o\">=</span><span class=\"s1\">&#39;Mark selected stories as published&#39;</span><span class=\"p\">,</span>\n<span class=\"p\">)</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_published</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\">queryset</span><span class=\"p\">):</span>\n    <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">status</span><span class=\"o\">=</span><span class=\"s1\">&#39;p&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>这就相当于直接在函数上设置一些属性（用原来的、较长的名字）：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_published</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\">queryset</span><span class=\"p\">):</span>\n    <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">status</span><span class=\"o\">=</span><span class=\"s1\">&#39;p&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">make_published</span><span class=\"o\">.</span><span class=\"n\">allowed_permissions</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;publish&#39;</span><span class=\"p\">]</span>\n<span class=\"n\">make_published</span><span class=\"o\">.</span><span class=\"n\">short_description</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;Mark selected stories as published&#39;</span>\n</code></pre></div>\n<p>使用这个装饰器并不是制作一个动作函数的必要条件，但在你的源码中使用它而不使用参数作为标记来识别函数的目的是很有用的：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"nd\">@admin</span><span class=\"o\">.</span><span class=\"n\">action</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">make_inactive</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\">queryset</span><span class=\"p\">):</span>\n    <span class=\"n\">queryset</span><span class=\"o\">.</span><span class=\"n\">update</span><span class=\"p\">(</span><span class=\"n\">is_active</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>在这种情况下，它将不会给函数添加任何属性。</p>\n</dd></dl>\n\n</section>","rootId":"admin-actions","toc":[{"title":"编写动作","anchor":"writing-actions","children":[{"title":"编写动作函数","anchor":"writing-action-functions","children":[]},{"title":"在 ModelAdmin 中添加动作","anchor":"adding-actions-to-the-modeladmin","children":[]},{"title":"处理动作中的错误","anchor":"handling-errors-in-actions","children":[]}]},{"title":"进阶动作技巧","anchor":"advanced-action-techniques","children":[{"title":"作为 ModelAdmin 方法的动作","anchor":"actions-as-modeladmin-methods","children":[]},{"title":"提供中间页的动作","anchor":"actions-that-provide-intermediate-pages","children":[]},{"title":"在整个站点提供动作","anchor":"making-actions-available-site-wide","children":[]},{"title":"禁用动作","anchor":"disabling-actions","children":[{"title":"禁用全站点动作","anchor":"disabling-a-site-wide-action","children":[]},{"title":"禁用特定 ModelAdmin 的所有动作","anchor":"disabling-all-actions-for-a-particular-modeladmin","children":[]},{"title":"有条件地启用或禁用动作","anchor":"conditionally-enabling-or-disabling-actions","children":[]}]},{"title":"设置动作的权限","anchor":"setting-permissions-for-actions","children":[]}]},{"title":"action 装饰器","anchor":"the-action-decorator","children":[]}],"breadcrumbs":[{"docname":"ref/index","title":"API 参考","url":"/zh-hans/4.1/ref/"},{"docname":"ref/contrib/index","title":"contrib 包","url":"/zh-hans/4.1/ref/contrib/"},{"docname":"ref/contrib/admin/index","title":"Django 管理站点","url":"/zh-hans/4.1/ref/contrib/admin/"}],"prev":{"docname":"ref/contrib/admin/index","title":"Django 管理站点","url":"/zh-hans/4.1/ref/contrib/admin/"},"next":{"docname":"ref/contrib/admin/filters","title":"ModelAdmin List Filters","url":"/zh-hans/4.1/ref/contrib/admin/filters/"},"formats":{"html":"/zh-hans/4.1/ref/contrib/admin/actions/","markdown":"/zh-hans/4.1/ref/contrib/admin/actions.md","json":"/zh-hans/4.1/ref/contrib/admin/actions.json"},"source":"https://github.com/django/django/blob/stable/4.1.x/docs/ref/contrib/admin/actions.txt","official":"https://docs.djangoproject.com/zh-hans/4.1/ref/contrib/admin/actions/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}