如何建立自訂 django-admin 命令

應用程式可以使用 manage.py 註冊它們自己的操作。例如,您可能想要為您正在發布的 Django 應用程式新增一個 manage.py 操作。在本文件中,我們將為 教學中的 polls 應用程式建立一個自訂 closepoll 命令。

若要執行此操作,請在應用程式中新增一個 management/commands 目錄。Django 會為該目錄中每個名稱不是以底線開頭的 Python 模組註冊一個 manage.py 命令。例如

polls/
    __init__.py
    models.py
    management/
        __init__.py
        commands/
            __init__.py
            _private.py
            closepoll.py
    tests.py
    views.py

在這個範例中,任何在 INSTALLED_APPS 中包含 polls 應用程式的專案都可以使用 closepoll 命令。

_private.py 模組將無法作為管理命令使用。

closepoll.py 模組只有一個要求 - 它必須定義一個擴展 BaseCommand 或其子類別Command 類別。

獨立腳本

自訂管理命令特別適用於執行獨立腳本,或從 UNIX crontab 或 Windows 排定的工作控制面板定期執行的腳本。

若要實作命令,請編輯 polls/management/commands/closepoll.py 使其如下所示

from django.core.management.base import BaseCommand, CommandError
from polls.models import Question as Poll


class Command(BaseCommand):
    help = "Closes the specified poll for voting"

    def add_arguments(self, parser):
        parser.add_argument("poll_ids", nargs="+", type=int)

    def handle(self, *args, **options):
        for poll_id in options["poll_ids"]:
            try:
                poll = Poll.objects.get(pk=poll_id)
            except Poll.DoesNotExist:
                raise CommandError('Poll "%s" does not exist' % poll_id)

            poll.opened = False
            poll.save()

            self.stdout.write(
                self.style.SUCCESS('Successfully closed poll "%s"' % poll_id)
            )

注意

當您使用管理命令並希望提供主控台輸出時,您應該寫入 self.stdoutself.stderr,而不是直接列印到 stdoutstderr。透過使用這些代理,可以更輕鬆地測試您的自訂命令。另請注意,您不需要使用換行字元結束訊息,它將會自動新增,除非您指定 ending 參數

self.stdout.write("Unterminated line", ending="")

可以使用 python manage.py closepoll <poll_ids> 呼叫新的自訂命令。

handle() 方法會接收一個或多個 poll_ids,並將每個 poll.opened 設定為 False。如果使用者引用了任何不存在的投票,則會引發 CommandErrorpoll.opened 屬性不存在於教學中,並為了這個範例而新增至 polls.models.Question

接受選用參數

可以透過接受其他命令列選項來輕鬆修改相同的 closepoll,以刪除給定的投票而不是關閉它。可以在 add_arguments() 方法中新增這些自訂選項,如下所示

class Command(BaseCommand):
    def add_arguments(self, parser):
        # Positional arguments
        parser.add_argument("poll_ids", nargs="+", type=int)

        # Named (optional) arguments
        parser.add_argument(
            "--delete",
            action="store_true",
            help="Delete poll instead of closing it",
        )

    def handle(self, *args, **options):
        # ...
        if options["delete"]:
            poll.delete()
        # ...

選項(在我們的範例中為 delete)在 handle 方法的 options dict 參數中可用。請參閱 argparse Python 文件,以取得有關 add_argument 用法的更多資訊。

除了能夠新增自訂命令列選項之外,所有 管理命令都可以接受一些預設選項,例如 --verbosity--traceback

管理命令和語言環境

預設情況下,管理命令會使用目前作用中的語言環境執行。

如果由於某些原因,您的自訂管理命令必須在沒有作用中的語言環境的情況下執行(例如,防止翻譯內容被插入資料庫),請使用 @no_translations 裝飾器在您的 handle() 方法上停用翻譯

from django.core.management.base import BaseCommand, no_translations


class Command(BaseCommand):
    ...

    @no_translations
    def handle(self, *args, **options): ...

由於停用翻譯需要存取已設定的設定,因此裝飾器無法用於在沒有已設定的設定下運作的命令。

測試

有關如何測試自訂管理命令的資訊,請參閱測試文件

覆寫命令

Django 會先註冊內建命令,然後在 INSTALLED_APPS 中反向搜尋命令。在搜尋期間,如果命令名稱與已註冊的命令重複,則新發現的命令會覆寫第一個命令。

換句話說,若要覆寫命令,新命令必須具有相同的名稱,而且其應用程式必須在 INSTALLED_APPS 中位於被覆寫的命令的應用程式之前。

可以透過在您的專案的其中一個應用程式中建立新命令(在 INSTALLED_APPS 中排在第三方應用程式之前),並匯入被覆寫命令的 Command,來在新的名稱下提供意外被覆寫的第三方應用程式的管理命令。

命令物件

class BaseCommand[原始碼]

所有管理命令最終都由此衍生而來的基礎類別。

如果您想要存取所有剖析命令列引數並找出要呼叫的回應程式碼的機制,請使用這個類別;如果您不需要變更任何行為,請考慮使用它的子類別之一。

子類化 BaseCommand 類別需要您實作 handle() 方法。

屬性

所有屬性都可以在您的衍生類別中設定,並可以在 BaseCommand子類別中使用。

BaseCommand.help

命令的簡短描述,當使用者執行命令 python manage.py help <command> 時,將會列印在說明訊息中。

BaseCommand.missing_args_message

如果您的命令定義了強制性的位置引數,您可以在引數遺失的情況下自訂傳回的錯誤訊息。預設值由 argparse 輸出(「引數太少」)。

BaseCommand.output_transaction

一個布林值,指示命令是否輸出 SQL 陳述式;如果為 True,輸出將會自動以 BEGIN;COMMIT; 包裝。預設值為 False

BaseCommand.requires_migrations_checks

一個布林值;如果為 True,如果磁碟上的移轉集與資料庫中的移轉不符,則命令會列印警告。警告不會阻止命令執行。預設值為 False

BaseCommand.requires_system_checks

一個標籤的列表或元組,例如 [Tags.staticfiles, Tags.models]。在執行命令之前,會先檢查在所選標籤中註冊的系統檢查是否有錯誤。可以使用 '__all__' 值來指定應執行所有系統檢查。預設值為 '__all__'

BaseCommand.style

一個實例屬性,在寫入 stdoutstderr 時,有助於建立彩色輸出。例如:

self.stdout.write(self.style.SUCCESS("..."))

請參閱 語法著色,以了解如何修改調色盤,並查看可用的樣式(使用該節中描述的「角色」的大寫版本)。

如果您在執行命令時傳遞 --no-color 選項,所有 self.style() 呼叫都會傳回未著色的原始字串。

BaseCommand.suppressed_base_arguments

在說明輸出中要抑制的預設命令選項。這應該是一組選項名稱(例如 '--verbosity')。抑制選項的預設值仍然會被傳遞。

方法

BaseCommand 有一些可以覆寫的方法,但只有 handle() 方法必須實作。

在子類別中實作建構子

如果您在 BaseCommand 的子類別中實作 __init__,您必須呼叫 BaseCommand__init__

class Command(BaseCommand):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # ...
BaseCommand.create_parser(prog_name, subcommand, **kwargs)[來源]

傳回一個 CommandParser 實例,它是 ArgumentParser 子類別,針對 Django 進行了一些自訂。

您可以覆寫此方法並使用 ArgumentParser 參數的 kwargs 呼叫 super() 來客製化實例。

BaseCommand.add_arguments(parser)[來源]

新增剖析器引數的進入點,以處理傳遞給命令的命令列引數。自訂命令應覆寫此方法,以新增命令接受的位置引數和可選引數。直接子類別化 BaseCommand 時,不需要呼叫 super()

BaseCommand.get_version()[來源]

傳回 Django 版本,該版本對於所有內建 Django 命令都應該是正確的。使用者提供的命令可以覆寫此方法以傳回他們自己的版本。

BaseCommand.execute(*args, **options)[來源]

嘗試執行此命令,如果需要,會執行系統檢查(如 requires_system_checks 屬性所控制)。如果命令引發 CommandError,它會被攔截並列印到 stderr

在程式碼中呼叫管理命令

不應直接從您的程式碼呼叫 execute() 來執行命令。請改用 call_command()

BaseCommand.handle(*args, **options)[來源]

命令的實際邏輯。子類別必須實作此方法。

它可以傳回一個字串,該字串將列印到 stdout(如果 output_transactionTrue,則會以 BEGIN;COMMIT; 包裝)。

BaseCommand.check(app_configs=None, tags=None, display_num_errors=False, include_deployment_checks=False, fail_level=checks.ERROR, databases=None)[來源]

使用系統檢查框架來檢查整個 Django 專案中潛在的問題。嚴重的問題會以 CommandError 引發;警告會輸出到 stderr;次要通知會輸出到 stdout

如果 app_configstags 都為 None,則會執行所有系統檢查,但部署和資料庫相關的檢查除外。tags 可以是檢查標籤的列表,例如 compatibilitymodels

您可以傳遞 include_deployment_checks=True 來執行部署檢查,並在 databases 中列出資料庫別名,以對其執行資料庫相關的檢查。

BaseCommand 子類別

class AppCommand

一個管理命令,它採用一個或多個已安裝的應用程式標籤作為引數,並對每個標籤執行某些操作。

子類別必須實作 handle_app_config(),而不是實作 handle(),對於每個應用程式,此方法將被呼叫一次。

AppCommand.handle_app_config(app_config, **options)

app_config 執行命令的操作,它將是一個 AppConfig 實例,對應於命令列中給定的應用程式標籤。

class LabelCommand

一個管理命令,它在命令行上接受一個或多個任意參數(標籤),並對每個參數執行操作。

子類別必須實作 handle_label(),而不是實作 handle()。對於每個標籤,`handle_label()` 會被調用一次。

LabelCommand.label

一個字串,描述傳遞給命令的任意參數。該字串會被用於命令的使用說明文字和錯誤訊息中。預設值為 'label'

LabelCommand.handle_label(label, **options)

針對在命令行上給定的字串 label 執行命令的動作。

命令例外

exception CommandError(returncode=1)[原始碼]

例外類別,表示執行管理命令時發生問題。

如果從命令行控制台執行管理命令時引發此例外,它將被捕獲並轉換為格式良好的錯誤訊息輸出到適當的輸出流(即 stderr)。因此,引發此例外(並提供錯誤的合理描述)是表示命令執行過程中發生錯誤的首選方式。它接受可選的 returncode 參數,以自訂管理命令退出的狀態碼,並使用 sys.exit() 退出。

如果管理命令是通過 call_command() 從程式碼中調用,則需要您在必要時捕獲例外。

返回頂部