阅读: 11696 评论:0


我们可以通过manage.py编写和注册自定义的命令。

自定义的管理命令对于独立脚本非常有用,特别是那些使用Linux的crontab服务,或者Windows的调度任务执行的脚本。比如,你有个需求,需要定时清空某篇文章下面的评论,一种解决方案就是写一个django-admin命令,再写一个运行该命令的独立脚本,最后通过crontab服务,定时执行该脚本。

下面,我们将为教程最开始的第一个Django应用中的polls应用编写一个自定义的closepoll命令。

一、创建management/commands目录

首先,需向该应用添加一个management/commands目录。

Django将为该目录中名字没有以下划线开始的每个Python模块注册一个manage.py命令。也就是说,你每自定义一个命令,就要在目录下创建一个新的模块。

像这样:

  1. polls/
  2. __init__.py
  3. models.py
  4. management/
  5. __init__.py
  6. commands/
  7. __init__.py
  8. _private.py
  9. closepoll.py
  10. tests.py
  11. views.py

在Python 2上,请确保managementmanagement/commands两个目录都包含__init__.py文件,否则将检测不到你的命令。

在这个例子中,closepoll命令对任何项目都可用,只要它们的INSTALLED_APPS里包含polls应用。

_private.py因为以下划线开头,将不可以作为一个管理命令使用。

closepoll.py模块中只有一个要求:必须定义一个Command类并继承BaseCommand类或其子类。

二、编写命令的具体代码

要实现这个命令,在polls/management/commands/closepoll.py中添加代码如下:

  1. from django.core.management.base import BaseCommand, CommandError
  2. from polls.models import Question as Poll
  3. class Command(BaseCommand):
  4. help = '关闭指定问卷的投票功能'
  5. def add_arguments(self, parser):
  6. parser.add_argument('poll_id', nargs='+', type=int)
  7. def handle(self, *args, **options):
  8. for poll_id in options['poll_id']:
  9. try:
  10. poll = Poll.objects.get(pk=poll_id)
  11. except Poll.DoesNotExist:
  12. raise CommandError('Poll "%s" does not exist' % poll_id)
  13. poll.opened = False
  14. poll.save()
  15. self.stdout.write(self.style.SUCCESS('Successfully closed poll "%s"' % poll_id))

每一个自定义的命令,都要自己实现handle()方法,这个方法是命令的核心业务处理代码,你的命令功能要通过它来实现。而add_arguments()则用于帮助处理命令行的参数,如果没有参数,可以不写这个方法。

注意:当你使用管理命令并希望提供控制台输出时,你应该写到self.stdoutself.stderr,而不能直接打印到stdout和stderr。另外,你不需要在消息的末尾加上换行符,它将被自动添加,除非你指定ending参数:self.stdout.write("Unterminated line", ending='')

三、执行命令的方式

调用格式:python manage.py 自定义命令名 <参数列表>

可以使用python manage.py closepoll调用上面的自定义命令。

四、可选参数

通过接收额外的命令行选项,可以简单地修改closepoll来删除一个给定的poll而不是关闭它。这些自定义的选项可以像下面这样添加到add_arguments()方法中:

  1. class Command(BaseCommand):
  2. def add_arguments(self, parser):
  3. # Positional arguments
  4. parser.add_argument('poll_id', nargs='+', type=int)
  5. # Named (optional) arguments
  6. parser.add_argument(
  7. '--delete',
  8. action='store_true',
  9. dest='delete',
  10. default=False,
  11. help='Delete poll instead of closing it',
  12. )
  13. def handle(self, *args, **options):
  14. # ...
  15. if options['delete']:
  16. poll.delete()
  17. # ...