編寫自定義 django-admin 命令

2021-12-31 IDC運維管理平臺
之前應用戶要求,給 idcops 設備信息新增一個設備高度的欄位(Height)單位為U(1U=1.75英寸[4.445公分])。這個欄位是根據設備當前佔用的U位數量來動態計算並寫入資料庫的,方便一次性從資料庫直接查詢出來從而提升系統的性能。 

上面的場景,引出了本文主題,用戶升級系統之後,如何能通過命令來修復設備信息中舊設備信息的設備高度。


按要求創建命令目錄結構

給 django 應用加命令其實很簡單,只需要在應用程式中添加一個 management/commands 目錄。Django 會給目錄下的每個 Python 模塊註冊一個 manage.py 命令,這個命令的名字不以下劃線開頭。例如:

idcops/
    __init__.py
    models.py
    management/
        __init__.py
        commands/
            __init__.py
            _private.py
            fixdevicedata.py
    tests.py
    views.py

_private.py 模塊將不會作為管理命令使用。fixdevicedata.py 必須定義 Command 類,該類繼承自 BaseCommand 或其 子類。

編寫自定義命令

以下是 fixdevicedata.py 自定義 django-admin 命令的源碼:

from queue import Queue
from threading import Thread

from django.core.management.base import BaseCommand, CommandError
from django.core.paginator import Paginator

from idcops.models import Device


class Command(BaseCommand):
    help = "更新所有設備的高度(U)、U位範圍"

    batch_size = 256

    def add_arguments(self, parser):
        parser.add_argument(
            '--size', type=int, action='store',
            dest='size', default=self.batch_size,
            help=f"指定每個線程處理多少條設備信息,默認是: {self.batch_size}/thread",
        )

    def fix_device_height(self, obj):
        # 主要業務邏輯
        height = obj.units.all().count()
        Device.objects.filter(pk=obj.pk).update(height=height)
        Device.objects.filter(pk=obj.pk).update(urange=obj.list_units())

    def handle(self, *args, **options):
        per_page = options['size']
        objects = Device.objects.filter()
        page = Paginator(objects, per_page=per_page)
        object_list = page.object_list
        try:
            if object_list.exists():
                q = Queue()

                def worker():
                    while True:
                        if q.empty():
                            return
                        else:
                            item = q.get()
                            self.fix_device_height(item)
                            q.task_done()
                for obj in object_list:
                    q.put(obj)
                threads = list()
                [
                    threads.append(Thread(target=worker, daemon=True))
                    for _ in range(page.num_pages)
                ]
                [t.start() for t in threads]
                [t.join() for t in threads]
                print(
                    f"threads number: {len(threads)} ({per_page}/thread), total: {page.count}"
                )
            else:
                print('No objects')
        except CommandError as e:
            raise(e)

add_arguments 給命令添加一個可選參數 size巧妙利用 Django 分頁,配合 queue 多線程處理業務邏輯


自定義命令效果

(env) PS D:\Personal\django-idcops> python .\manage.py fixdevicedata -h      
usage: manage.py fixdevicedata [-h] [--size SIZE] [--version] [-v {0,1,2,3}]
[--settings SETTINGS] [--pythonpath PYTHONPATH]
[--traceback] [--no-color]

更新所有設備的高度(U)、U位範圍

optional arguments:
-h, --help show this help message and exit
--size SIZE 指定每個線程處理多少條設備信息,默認是: 256/thread
--version show program's version number and exit
-v {0,1,2,3}, --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn't provided, the
DJANGO_SETTINGS_MODULE environment variable will be
used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g.
"/home/djangoprojects/myproject".
--traceback Raise on CommandError exceptions
--no-color Don't colorize the command output.
(env) PS D:\Personal\django-idcops>

(env) PS D:\Personal\django-idcops> python .\manage.py fixdevicedata --size 2
threads number: 4 (2/thread), total: 7
(env) PS D:\Personal\django-idcops> python .\manage.py fixdevicedata
threads number: 1 (256/thread), total: 7

一共7條數據,共啟動了4個線程,每個線程能處理2條數據一共7條數據,共啟動了1個線程,每個線程能處理256條數據


總結:

Django 會給目錄下的每個 Python 模塊註冊一個 manage.py 命令。所以,一個模塊只做一類命令的業務。批量業務數據量比較大,可以使用多線程來加速業務的處理。


相關焦點

  • Django 2.1.7 Admin - 註冊模型、自定義顯示列表欄位
    使用Django的管理模塊,需要按照如下步驟操作:1.管理界面本地化 2.創建管理員 3.註冊模型類 4.自定義管理頁面1.管理界面本地化本地化是將顯示的語言、時間等使用本地的習慣,這裡的本地化就是進行中國化,中國大陸地區使用簡體中文
  • django admin 主題框架 simpleui 發布更新,更貼近國人的操作習慣
    simpleui 是一個基於django admin的主題,主要是為了美化和簡化django內置的admin。
  • django-admin和manage.py用法
    開篇話:我們在Django開發過程中,命令行執行最多的應該就是python manage.py <command>,今天聊聊manage.py這個命令。記錄要點:django-admin和manage.py 能做同樣的事情 像我們常用的python manage.py runserver,用django-admin也可以操作:django-admim runserver 注意: django-admin需要提前提前配置好DJANGO_SETTINGS_MODULE環境變量
  • 向Django Admin添加圖表
    擴展 django-adminDjango後臺管理應用程式由ModelAdmin類組成。這些表示後臺管理界面中模型的可視視圖。默認情況下,一個ModelAdmin類有5個默認視圖:當你想要查看一個特定的模型時,ChangeList視圖是默認的後臺管理視圖。
  • 一個完整的Django入門指南
    啟動一個新項目,執行下面的命令來創建一個新的 Django 項目:django-admin startproject myproject命令行工具django-admin會在安裝Django的時候一起自動安裝好。執行了上面的命令以後,系統會為Django項目生成基礎文件夾結構。
  • 如何輕鬆了解 Python 必學的 django 框架?
    ,這需要編寫自定義 action 實現。本文基於 django 官方英文文檔梳理了一下自定義管理操作需要做的工作,方便快速了解自定義管理操作的實現過程。編寫 Admin actions 下面舉例說明如何編寫Admin action。
  • Django+Vue項目學習第一篇:django後臺搭建
    版本C:\Users\HanMK\Desktop>python -m django --version2.2.1cd 到一個你想放置你代碼的目錄,然後運行以下命令C:\Users\HanMK\Desktop>django-admin startproject mysite將會在當前目錄下創建一個
  • Django入門案例:圖書管理系統
    startproject booktestcd booktestdjango-admin startapp book_managerment帶路徑演示:(django) E:\python_Projects\django_demo>django-admin
  • Django第二十八課
    本部分內容參考B站UP再敲一行代碼的Django2教程[1]⚠️:多圖預警第二十八課 自定義用戶模型在上節課登錄功能中,我們提到了個人資料。這節課我們繼續講述關於個人資料中的用戶自定義內容。1.5 將自定義模型加入admin打開後臺,發現我們定義的user並沒有加入後臺。
  • 「原創」Django第五章、模型建立與遷移
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫模型建立與遷移回顧上一章中,我們介紹了模型層的基本結構和基本欄位。別忘了,在介紹Django特點的時候,我們知道Django適合做內容,所以基於此特點,我們編寫一個博客豈不樂哉。畢竟博客中最需要的就是文章嘛,好,閒話少敘,我們開始。
  • django-simpleui 2.1.2 發布,修復眾多 bug 和小幅度功能增加
    simpleui是django admin theme 主題 django-simpleui 是一個基於element-ui+vue
  • Django的INSTALLED_APPS中應該寫app名,還是AppConfig子類?
    屬性裡4個標紅的屬性可以自定義的,兩個標紅方法是可以重寫的。name:django應用的完整python路徑,eg.'django.contrib.admin',在初始化參數中由app_name參數指定。label:app的標籤,這個名字必需獨一無二,如果不設置即為app名。verbose_name: app的別名,如果不設置即為app首字母大寫形式。
  • Django 2.0 項目實戰: 擴展Django自帶User模型,實現用戶註冊與登錄
    由於Django Auth自帶的User模型欄位有限,我們還需要自定義模型UserProfile對其擴展。自定義的UserProfile模型user: 與User是1對1關係org:用戶名telephone: 電話mod_date: 最後修改日期。
  • Django實戰多語言
    將需要翻譯的內容添加trans標籤,例如:<li><a href="{% url 'index' %}">{% trans "Home" %}</a></li>生成三種語言對應的內容django-admin
  • 「原創」Django第六章、模型操作
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫模型的操作回顧上一章中我們建立了一個博客文章的模型,然後通過數據遷移建立我們對應中的資料庫表,這一章我們接著說模型的操作
  • Django官方為什麼沒有標準項目結構
    project在使用django-admin startproject命令後就會創建這樣的目錄文件,如下:mysite/ manage.py mysite/ __init__.py settings.py urls.py asgi.py
  • 8個能提高Django開發效率的Python包
    創建出色的管理命令:django-clickDjango-click,基於Click模塊(我們之前推薦過兩次),可以用來幫助您編寫Django管理命令。這個庫沒有大量的文檔,但是它的存儲庫中有一個測試命令的目錄,非常有用。
  • 使用 Django 進行測試驅動開發
    ,然後編寫代碼來滿足測試用例,具體包含以下步驟:通常情況下,我們都是先寫代碼,然後編寫測試用例,因此測試驅動開發是反直覺的,那為什麼還要這麼做呢?先編寫測試用例可確保您的原始碼始終具有可測試性,它還保證隨著代碼庫的增長,測試覆蓋率始終保持在合理的百分比。然而,測試驅動開發也不是銀彈,以下情形並不適合測試驅動開發:當需求不明確時,有時續期會隨著開發的進行而逐漸明確,在這種情況下最初編寫的任何測試可能會過時。開發的目的是為了證明某一概念時——例如在黑客馬拉松期間,測試通常不是優先事項。
  • python程式設計師嘔心瀝血整理 Django 優秀資源大全
    django-model-report, star:156 - 一個集成了 highcharts 的 Django 報表應用。django-report-builder, star:453 - Django ORM 的一個用戶界面。能構建自定義的查詢並顯示結果。目標用戶是系統管理員及不會編程的終端用戶。
  • Flask 偏函數、g對象、flask-session、資料庫連接池、信號、自製命令、flask-admin
    import Flask, current_app, flash, render_templatefrom flask.signals import _signalsapp = Flask(import_name=__name__)# 自定義信號