django實現自定義manage命令的擴展
- 2019 年 10 月 3 日
- 筆記
在Django開發過程中我們都用過django-admin.py和manage.py命令。
django-admin.py是一個命令行工具,可以執行一些管理任務,比如創建Django項目。而manage.py是在創建每個Django project時自動添加在項目目錄下的,只是對manage.py的一個簡單包裝,其功能是將Django project放到sys.path目錄中,同時設置DJANGO_SETTINGS_MODULE環境變量為當前project的setting.py文件。
Django 對於命令的添加有自己的一套規範,我們可以為每個app 指定命令。簡單來書就是我們在使用manage.py文件執行命令的時候,可以自定製自己的命令,來實現命令的擴充。
對於自定義Command我們從兩方面介紹一是內部執行原理,二是如何實行自定義Command
一、內部原理實現
django-admin.py調用django.core.management來執行命令:
創建django項目會自動生成manage.py文件:
import os import sys def main(): os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gaoyou.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: raise ImportError( "Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?" ) from exc execute_from_command_line(sys.argv) if __name__ == '__main__': main()
excute_from_command_line()函數會根據命令行參數解析出命令的名稱,根據命令名稱調用相應的Command執行命令。Command位於各個管理模塊的commands模塊下面。
commands的創建方法:
1、在app內創建一個名字為:management文件夾(在你自己指定的應用下創建即可) 2、在management文件夾裏面創建名為:commands的文件夾 3、在commands文件夾下創建名為:任意py文件(啟動的時候就是根據該文件名進行啟動的,注意:commands目錄內都包含__init__.py
文件)
此時py文件名就是你的自定製命令,我們可以使用下面方式進行執行
python manage.py 命令名(即任意py文件名不用加.py) #類似我們遷移數據庫命令 #python manage.py makemigrations #python manage.py migrate
所謂管理模塊,是指在app模塊下的名字為management的模塊。Django通過django.core.management.find_management_module函數發現”管理模塊”:
django.core.management.find_management_module() def find_management_module(app_name): """ Determines the path to the management module for the given app_name, without actually importing the application or the management module. Raises ImportError if the management module cannot be found for any reason. """ parts = app_name.split('.') parts.append('management') parts.reverse() part = parts.pop() path = None
然後通過django.core.management.find_commands函數找到命令類。find_commands函數會在管理模塊下查找.py文件,並將.py文件的名稱匹配到命令名稱:
def find_commands(management_dir): """ Given a path to a management directory, returns a list of all the command names that are available. Returns an empty list if no commands are defined. """ command_dir = os.path.join(management_dir, 'commands') try: return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')] except OSError: return []
最後,通過django.core.management.load_command_class函數加載該.py文件中的Command類:
def load_command_class(app_name, name): """ Given a command name and an application name, returns the Command class instance. All errors raised by the import process (ImportError, AttributeError) are allowed to propagate. """ module = import_module('%s.management.commands.%s' % (app_name, name)) return module.Command()
在執行命令的時候,會執行相應Command類的handle方法。所有的Command類都應該是django.core.management.base.BaseCommand的直接或間接子類。
二、自定義應用
Django的Command命令是要放到我們創建app下的management/commands目錄下的(需自己手動創建該文件目錄)。
注意:請確保management/commands目錄下包含__init__.py
文件
首先對於文件名可以自行定義沒有要求,內部需要定義一個Command類並繼承BaseCommand類或其子類。
- 它必須定義一個Command類並擴展自BaseCommand或其 子類。
- 其中help是command功能作用簡介,handle函數是主處理程序,add_arguments函數是用來接收可選參數的(如果沒有參數該方法可以不寫)
我們通過在輸入命令後再控制台輸出一個hello world為例:
task.py
from django.core.management.base import BaseCommand, CommandError from django.db import models class Command(BaseCommand): help = '每日凌晨對當天數據庫進行更新' def handle(self, *args, **options): print('hello world')
在Terminal控制台將目錄切換到你創建的Django項目目錄下執行:python manage.py task
執行後即可在控制台看到輸出hello world 說明自定義Commond成功!!!
如果在輸入命令想要輸出參數怎麼辦呢?例如:python mange.py task 參數
task.py
from django.core.management.base import BaseCommand, CommandError from django.db import models class Command(BaseCommand): help = '每日凌晨對當天數據庫進行更新' # 接收參數 def add_arguments(self, parser): parser.add_argument('offset', type=int, help='天數轉移量') def handle(self, *args, **options): offset = options['offset'] # 拿到參數的值 print(offset) print('hello world') self.stdout.write(self.style.SUCCESS('{} Successfully {}'.format('接收成功', offset))) #可以自定製在控制台輸出的內容
在Terminal控制台將目錄切換到你創建的Django項目目錄下執行:python manage.py task 1314
自定義django-admin命令可以用來設置一些定時腳本,讓其在指定的時間內進行運行