應用能夠經過manage.py
註冊它們本身的動做。例如,你可能想爲你正在發佈的Django應用添加一個manage.py
動做。在本頁文檔中,咱們將爲教程中的 polls
應用構建一個自定義的 closepoll
命令。html
要作到這點,只需向該應用添加一個management/commands
目錄。Django將爲該目錄中名字沒有如下劃線開始的每一個Python模塊註冊一個manage.py
命令。例如:python
polls/ __init__.py models.py management/ __init__.py commands/ __init__.py _private.py closepoll.py tests.py views.py
在Python 2上,請確保management
和management/commands
兩個目錄都包含__init__.py
文件,不然將檢測不到你的命令。數據庫
在這個例子中,closepoll
命令對任何項目均可使用,只要它們在INSTALLED_APPS
裏包含polls
應用。django
_private.py
將不能夠做爲一個管理命令使用。app
closepoll.py
模塊只有一個要求 – 它必須定義一個Command
類並擴展自BaseCommand
或其 子類。框架
獨立的腳本函數
自定義的管理命令主要用於運行獨立的腳本或者UNIX crontab和Windows週期任務控制面板週期性執行的腳本。測試
要實現這個命令,需將polls/management/commands/closepoll.py
編輯成這樣:ui
from django.core.management.base import BaseCommand, CommandError from polls.models import Poll class Command(BaseCommand): help = 'Closes the specified poll for voting' def add_arguments(self, parser): parser.add_argument('poll_id', nargs='+', type=int) def handle(self, *args, **options): for poll_id in options['poll_id']: 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('Successfully closed poll "%s"' % poll_id)
Changed in Django 1.8: 在Django 1.8以前,管理命令基於optparse模塊,位置參數傳遞給*args,可選參數傳遞給**options。如今,管理命令使用argparse解析參數,默認全部的參數都傳遞給**options,除非你命名你的位置參數爲args(兼容模式)。對於新的命令,鼓勵你僅僅使用**options。
注this
當你使用管理命令並但願提供控制檯輸出時,你應該寫到
self.stdout
和self.stderr
,而不能直接打印到stdout
和stderr
。經過使用這些代理方法,測試你自定義的命令將變得很是容易。還請注意,你不須要在消息的末尾加上一個換行符,它將被自動添加,除非你指定ending
參數:
self.stdout.write("Unterminated line", ending='')
新的自定義命令可使用python manage.py closepoll <poll_id>
調用。
handle()
接收一個或多個poll_ids
併爲他們中的每一個設置 poll.opened
爲False
。若是用戶訪問任何不存在的polls
,將引起一個CommandError
。poll.opened
屬性在教程中並不存在,只是爲了這個例子將它添加到polls.models.Poll
中。
經過接收額外的命令行選項,能夠簡單地修改closepoll
來刪除一個給定的poll
而不是關閉它。這些自定義的選項能夠像下面這樣添加到 add_arguments()
方法中:
class Command(BaseCommand): def add_arguments(self, parser): # Positional arguments parser.add_argument('poll_id', nargs='+', type=int) # Named (optional) arguments parser.add_argument('--delete', action='store_true', dest='delete', default=False, help='Delete poll instead of closing it') def handle(self, *args, **options): # ... if options['delete']: poll.delete() # ...
Changed in Django 1.8: 以前,只支持標準的optparse庫,你必須利用optparse.make_option()擴展命令option_list變量。
選項(在咱們的例子中爲delete
)在handle
方法的options
字典參數中能夠訪問到。更多關於add_argument
用法的信息,請參考argparse
的Python 文檔。
除了能夠添加自定義的命令行選項, 管理命令還能夠接收一些默認的選項,例如--verbosity
和--traceback
。
默認狀況下,BaseCommand.execute()
方法使轉換失效,由於某些與Django一塊兒的命令完成的任務要求一個與項目無關的語言字符串(例如,面向用戶的內容渲染和數據庫填入)。
Changed in Django 1.8: 在以前的版本中,Django強制使用"en-us"區域設置而不是使轉換失效。
若是,出於某些緣由,你的自定義的管理命令須要使用一個固定的區域設置,你須要在你的handle()
方法中利用I18N支持代碼提供的函數手工地啓用和停用它:
from django.core.management.base import BaseCommand, CommandError from django.utils import translation class Command(BaseCommand): ... can_import_settings = True def handle(self, *args, **options): # Activate a fixed locale, e.g. Russian translation.activate('ru') # Or you can activate the LANGUAGE_CODE # chosen in the settings: from django.conf import settings translation.activate(settings.LANGUAGE_CODE) # Your command logic here ... translation.deactivate()
另外一個須要多是你的命令只是簡單地應該使用設置中設置的區域設置且Django應該保持不讓它停用。你可使用BaseCommand.leave_locale_alone
選項實現這個功能。
雖然上面描述的場景能夠工做,可是考慮到系統管理命令對於運行非統一的區域設置一般必須很是當心,因此你可能須要:
確保運行命令時USE_I18N
設置永遠爲True
(this is a good example of the potential problems stemming from a dynamic runtime environment that Django commands avoid offhand by deactivating translations)。
Review the code of your command and the code it calls for behavioral differences when locales are changed and evaluate its impact on predictable behavior of your command.
關於如何測試自定義管理命令的信息能夠在測試文檔中找到。
class BaseCommand
全部管理命令最終繼承的基類。
若是你想得到解析命令行參數並在響應中如何調用代碼的全部機制,可使用這個類;若是你不須要改變這個行爲,請考慮使用它的子類。
繼承BaseCommand
類要求你實現handle()
方法。
全部的屬性均可以在你派生的類中設置,並在BaseCommand
的子類中使用。
BaseCommand.args
一個字符串,列出命令接收的參數,適合用於幫助信息;例如,接收一個應用名稱列表的命令能夠設置它爲‘<app_label app_label ...>
’。
Deprecated since version 1.8: 如今,應該在add_arguments()方法中完成,經過調用parser.add_argument()方法。參見上面的closepoll例子。
BaseCommand.can_import_settings
一個布爾值,指示該命令是否須要導入Django的設置的能力;若是爲True
,execute()
將在繼續以前驗證這是否可能。默認值爲True
。
BaseCommand.help
命令的簡短描述,當用戶運行python manage.py help <command>
命令時將在幫助信息中打印出來。
BaseCommand.missing_args_message
New in Django 1.8.
若是你的命令定義了必需的位置參數,你能夠自定義參數缺失時返回的錯誤信息。默認是由argparse
輸出的 (「too few arguments」)。
BaseCommand.option_list
這是optparse選項列表,將賦值給命令的OptionParser用於解析命令。
Deprecated since version 1.8: 如今,你應該覆蓋`add_arguments()`方法來添加命令行接收的自定義參數。參見上面的例子。
BaseCommand.output_transaction
一個布爾值,指示命令是否輸出SQL語句;若是爲True
,輸出將被自動用BEGIN;
和COMMIT;
封裝。默認爲False
。
BaseCommand.requires_system_checks
New in Django 1.7.
一個布爾值;若是爲True
,在執行該命令以前將檢查整個Django項目是否有潛在的問題。若是requires_system_checks
缺失,則使用requires_model_validation
的值。若是後者的值也缺失,則使用默認值(True
)。同時定義requires_system_checks
和requires_model_validation
將致使錯誤。
BaseCommand.requires_model_validation
Deprecated since version 1.7: 被requires_system_checks代替
一個布爾值;若是爲True
,將在執行命令以前做安裝的模型的驗證。默認爲True
。若要驗證一個單獨應用的模型而不是所有應用的模型,能夠調用在handle()
中調用validate()
。
BaseCommand.leave_locale_alone
一個布爾值,指示設置中的區域設置在執行命令過程當中是否應該保持而不是強制設成‘en-us’。
默認值爲False
。
若是你決定在你自定義的命令中修改該選項的值,請確保你知道你正在作什麼。 若是它建立對區域設置敏感的數據庫內容,這種內容不該該包含任何轉換(好比django.contrib.auth
權限發生的狀況),由於將區域設置變成與實際上默認的‘en-us’ 不一樣可能致使意外的效果。更進一步的細節參見上面的管理命令和區域設置一節。
當can_import_settings
選項設置爲False
時,該選項不能夠也爲False
,由於嘗試設置區域設置須要訪問settings
。這種狀況將產生一個CommandError
。
BaseCommand
有幾個方法能夠被覆蓋,可是隻有handle()
是必須實現的。
在子類中實現構造函數
若是你在
BaseCommand的
子類中實現__init__
,你必須調用BaseCommand
的__init__
:
class Command(BaseCommand): def __init__(self, *args, **kwargs): super(Command, self).__init__(*args, **kwargs) # ...
BaseCommand.add_arguments(parser)
New in Django 1.8.
添加解析器參數的入口,以處理傳遞給命令的命令行參數。自定義的命令應該覆蓋這個方法以添加命令行接收的位置參數和可選參數。當直接繼承BaseCommand
時不須要調用super()
。
BaseCommand.get_version()
返回Django的版本,對於全部內建的Django命令應該都是正確的。用戶提供的命令能夠覆蓋這個方法以返回它們本身的版本。
BaseCommand.execute(*args, **options)
執行這個命令,若是須要則做系統檢查(經過 requires_system_checks
屬性控制)。若是該命令引起一個CommandError
,它將被截斷並打印到標準錯誤輸出。
在你的代碼中調用管理命令
不該該在你的代碼中直接調用
execute()
來執行一個命令。請使用call_command
。
BaseCommand.handle(*args, **options)
命令的真正邏輯。子類必須實現這個方法。
BaseCommand.check(app_configs=None, tags=None, display_num_errors=False)
New in Django 1.7.
利用系統的檢測框架檢測所有Django項目的潛在問題。嚴重的問題將引起CommandError
;警告會輸出到標準錯誤輸出;次要的通知會輸出到標準輸出。
若是app_configs
和tags
都爲None
,將進行全部的系統檢查。tags
能夠是一個要檢查的標籤列表,好比compatibility
或models
。
BaseCommand.validate(app=None, display_num_errors=False)
Deprecated since version 1.7: 被check命令代替
若是app
爲None
,那麼將檢查安裝的全部應用的錯誤。
class AppCommand
這個管理命令接收一個或多個安裝的應用標籤做爲參數,並對它們每個都作一些動做。
子類不用實現handle()
,但必須實現handle_app_config()
,它將會爲每一個應用調用一次。
AppCommand.handle_app_config(app_config, **options)
對app_config
完成命令行的動做,其中app_config
是AppConfig
的實例,對應於在命令行上給出的應用標籤。
Changed in Django 1.7:
之前,AppCommand子類必須實現
handle_app(app, **options)
,其中app
是一個模型模塊。新的API能夠不須要模型模塊來處理應用。遷移的最快的方法以下:
def handle_app_config(app_config, **options): if app_config.models_module is None: return # Or raise an exception. app = app_config.models_module # Copy the implementation of handle_app(app_config, **options) here.
然而,你能夠經過直接使用
app_config
的屬性來簡化實現。
class LabelCommand
這個管理命令接收命令行上的一個或多個參數(標籤),並對它們每個都作一些動做。
子類不用實現handle()
,但必須實現handle_label()
,它將會爲每一個標籤調用一次。
LabelCommand.handle_label(label, **options)
對label
完成命令行的動做,label
是命令行給出的字符串。
class NoArgsCommand
Deprecated since version 1.8: 使用BaseCommand代替,它默認也不須要參數。
這個命令不接收命令行上的參數。
子類不須要實現handle()
,但必須實現handle_noargs()
;handle()
自己已經被覆蓋以保證不會有參數傳遞給命令。
NoArgsCommand.handle_noargs(**options)
完成這個命令的動做
class CommandError
異常類,表示執行一個管理命令時出現問題。
若是這個異常是在執行一個來自命令行控制檯的管理命令時引起,它將被捕獲並轉換成一個友好的錯誤信息到合適的輸出流(例如,標準錯誤輸出);所以,引起這個異常(並帶有一個合理的錯誤描述)是首選的方式來指示在執行一個命令時某些東西出現錯誤。
若是管理命令從代碼中經過call_command調用,那麼須要時捕獲這個異常由你決定。
譯者:Django 文檔協做翻譯小組,原文:Adding custom commands。
本文以 CC BY-NC-SA 3.0 協議發佈,轉載請保留做者署名和文章出處。
Django 文檔協做翻譯小組人手緊缺,有興趣的朋友能夠加入咱們,徹底公益性質。交流羣:467338606。