• 自定义Django-admin管理命令


    django本身是有一些django-admin命令的,他们都是基于manage.py来使用的。

    比如,python3 manage.py createsuperuser xxx

               python3 manage.py makemigrations

               python3 manage.py migrate

               python3 manage.py dumpdata path.modle --pk num  # 将数据库中表名为modle,pk为 unm的数据导出来

               python3 manage.py loaddata xxx.json   # 将有表数据的json文件导入数据库

    等等...

    但是,更多时候,我们对于工程的操作,往往是需要自己定义一些命令的,以更方便的操控工程。所以,就有了自定义 django-admin 管理命令一说。

    举个简单的例子,fab 是可以用作在远程机器上执行命令的一个工具,有时候,我们会将部署服务的命令集成到 fabfile.py,这样,就可以使用 fab 命令去完成服务的部署了。但是 fab 往往是单独存在的,需要我们在terminal直接输入 fab 命令,这样跟整个工程的粘度,就不是很大了。所以我们会考虑将 fab 集成到 django-admin 里, 通过 python3 manage.py fab task:param remote_machine_address,的这类命令,直接实现服务的部署操作。

    对于自定义的 django-admin 的创建,本身并不难:

    首先:自定义的Django-admin管理命令本质上是一个python脚本文件,它的存放路径必须遵循一定的规范,一般位于app/management/commands目录。整个文件夹的布局如下所示:

    1. app01/
    2. __init__.py
    3. models.py
    4. management/
    5. __init__.py
    6. commands/
    7. __init__.py
    8. _private.py # 以下划线开头文件不能用作管理命令
    9. my_commands.py # 这个就是自定义的管理命令脚本,文件名即为命令名
    10. tests.py
    11. views.py

    这个布局是不能变的。这里注意,commands 文件夹下可以有多个py文件,基本上每个py文件的文件名,就是自定义管理命令的命令名称。所以,在一个commands里是可以创建出多条django-admin命令的。另外就是commands文件夹中,下划线开头的py文件,是不会被系统认定为django-admin命令的,所以像这种类型的文件都可以用来存储一些方法文件。

    django-admin的具体定义:

    每一个自定义的管理命令本质是一个Command类, 它继承了Django的Basecommand或其子类, 主要通过重写handle()方法实现自己的业务逻辑代码,而add_arguments()则用于帮助处理命令行的参数,如果运行命令时不需要额外参数,可以不写这个方法。

    1. from django.core.management.base import BaseCommand
    2. class Command(BaseCommand):
    3. # 帮助文本, 一般备注命令的用途及如何使用。
    4. help = 'Some help texts'
    5. # 处理命令行参数,可选
    6. def add_arguments(self, parser):
    7. pass
    8. # 核心业务逻辑
    9. def handle(self, *args, **options):
    10. pass

    这里注意 add_arguments() 这个函数中的参数,parser,它是个特殊的对象,使用方法类似于下面的演示。

    1. from django.core.management.base import BaseCommand
    2. class Command(BaseCommand):
    3. # 帮助文本, 一般备注命令的用途及如何使用。
    4. help = "Print Hello World!"
    5. # 给命令添加一个名为name的参数
    6. def add_arguments(self, parser):
    7. parser.add_argument('name')
    8. # 核心业务逻辑,通过options字典接收name参数值,拼接字符串后输出
    9. def handle(self, *args, **options):
    10. msg = 'Hello World ! '+ options['name']
    11. self.stdout.write(msg) 此时当你再次运行`python manage.py hello_world John`命令时,你将得到如下输出结果:

    其实,关于这个参数,还有更多的用法,例如:

    1. import datetime
    2. import logging
    3. import subprocess
    4. import textwrap
    5. from django.core.management.base import BaseCommand
    6. DEFAULT_DAYS = 7
    7. START_DATE = datetime.datetime(2018, 6, 24)
    8. _BUILD_TREE = "/bldmnt/storage61/release"
    9. _TERMINAL_METASTATES = ('failed')
    10. logger = logging.getLogger('webapps')
    11. class Command(BaseCommand):
    12. """
    13. This command takes 1 argument, buildtype
    14. """
    15. help = textwrap.dedent(__doc__).strip()
    16. def add_arguments(self, parser):
    17. # Named (optional) arguments
    18. parser.add_argument(
    19. '-b', '--buildtype',
    20. type=str,
    21. choices=('sb', 'ob'),
    22. required=True,
    23. help='Build type either SB or OB',
    24. )
    25. parser.add_argument(
    26. '--days', '-d',
    27. dest="days",
    28. default=DEFAULT_DAYS,
    29. help='Number of days to check storage. Default: %(default)s.',
    30. type=int,
    31. )
    32. def handle(self, *args, **options):
    33. """
    34. Entry point when management command is executed.
    35. """
    36. total_size = 0
    37. buildtype = options['buildtype']
    38. INTERVAL = options['days']
    39. END_DATE = START_DATE + datetime.timedelta(days=INTERVAL)
    40. DAYS_INTERVAL = datetime.timedelta(days=1)
    41. current_start = START_DATE

    他完全和 python 的 parser 这个模块,用法一致。

    关于这个模块的具体参数,及用法可以参考:

    python之parser.add_argument()用法——命令行选项、参数和子命令解析器_夏普通的博客-CSDN博客_parser.add_argument(

    添加 add_arguments 的方式,在写handle的时候,都是通过,options 取的,是当字典来用的。另外提一种,不添加 add_arguments 方法的方式,直接安位传参。

    1. import os
    2. from django.conf import settings
    3. from django.core.management.base import BaseCommand
    4. class Command(BaseCommand):
    5. def handle(self, *args, **options):
    6. os.system('%s %s' % (settings.FAB_CMD, ' '.join(args)))
    7. def run_from_argv(self, argv):
    8. parser = self.create_parser(argv[0], argv[1])
    9. options = parser.parse_args([])
    10. cmd_options = vars(options)
    11. cmd_options.pop('args', ())
    12. self.execute(*argv[2:], **cmd_options)
    13. def print_help(self, prog_name, subcommand):
    14. os.system('%s --help' % settings.FAB_CMD)

    只需要重写 run_from_argv 这个方法,这样会让 opthions 的内容变为空字典。在manage.py 后使用的时候,就直接按位传参就可以了。

    另外,再扯点fab命令,首先下载 fabric 包。

    然后就是 fabric 的使用,命令:fab --fabfile  xxx.py   task:param   remote_machine_address

    fab的使用,是必须有个配置文件的,这个文件放到工程的根目录且名为 fabfile.py 的时候,那么使用fab命令就可以不给 --fabfile 参数,如果是放到其他位置,或是叫其他名称,那就需要给 --fabfile 参数,以明确指定用哪个fab文件。

    对fab的一些参数的说明,可以参考:Python Fabric模块详解 - 君无颜 - 博客园

    看一个真实的fabfile:

    1. from fabric.api import env, sudo, task, run
    2. from fabric.context_managers import remote_tunnel, cd
    3. from fabric.utils import puts
    4. PROJECT_NAME = 'buildapi'
    5. SERVICE_ROOT_SB = '/service/buildapi-sb'
    6. SERVICE_ROOT_OB = '/service/buildapi-ob'
    7. BUILDAPI_ROOT = '/build/mts/buildapi'
    8. # Settings:
    9. env.roledefs = {
    10. 'sjc31': [
    11. ],
    12. 'wdc': [
    13. ],
    14. 'stage': [
    15. '
    16. ],
    17. }
    18. # Note: task(s) will be executed on hosts in the order listed
    19. env.roledefs['all'] = (env.roledefs['wdc'] + env.roledefs['sjc31'])
    20. set_common_settings()
    21. # Tasks:
    22. all = get_role_setter('all')
    23. sjc31 = get_role_setter('sjc31')
    24. wdc = get_role_setter('wdc')
    25. stage = get_role_setter('stage')
    26. sync = get_sync_task(PROJECT_NAME, BUILDAPI_ROOT)
    27. restart_sb = get_restart_task(PROJECT_NAME, SERVICE_ROOT_SB)
    28. restart_ob = get_restart_task(PROJECT_NAME, SERVICE_ROOT_OB)
    29. @task
    30. def deploy(rev=None, force=False, tunnel=False):
    31. """Deploy buildapi. Usage: deploy[:rev=REVISION][:force=1][:tunnel=1]"""
    32. paragraph()
    33. puts(hl('Deploying buildapi...'))
    34. if sync(rev):
    35. py38env(tunnel)
    36. restart_sb(force)
    37. restart_ob(force)
    38. else:
    39. puts(warn('No need to restart.'))
    40. @task
    41. def py38env(tunnel=False):
    42. """Create/upgrade the py38 virtualenv. Usage: py38env[:tunnel=1]"""
    43. if tunnel:
    44. tunnel_port = 10210
    45. with remote_tunnel(remote_port=tunnel_port,
    46. local_host="build-artifactory",
    47. local_port=80):
    48. sudo('/usr/bin/make -C %s -f ./py38env.mk '
    49. 'BUILD_ARTIFACTORY=127.0.0.1:%s'
    50. % (BUILDAPI_ROOT, tunnel_port))
    51. else:
    52. sudo('/usr/bin/make -C %s -f ./py38env.mk' % BUILDAPI_ROOT)
    53. deploy_check()
    54. @task
    55. def deploy_check():
    56. """Deploy test for django admin check command if setup correctly"""
    57. with cd(BUILDAPI_ROOT):
    58. run('./manage_sb.sh check')

  • 相关阅读:
    【STM32】电容触摸按键
    二重积分一般计算步骤
    2022年9月1日:在 Visual Studio Code 中使用 Git 版本控制工具(未完成)
    牛客网基础知识强化巩固-周结03
    StableSwarmUI 安装教程(详细)
    java中stringbuffer用法:StringBuffer实现高效字符串拼接
    java计算机毕业设计汉语言类网上考试系统MyBatis+系统+LW文档+源码+调试部署
    最长重复子数组
    CentOS7使用yum安装MySQL8.0教程
    【方向盘】Spring Boot 2.5.0正式发布,环境变量可指定前缀的功能很赞
  • 原文地址:https://blog.csdn.net/m0_46900715/article/details/126886046