Django

Code

Changeset 6047

Show
Ignore:
Timestamp:
09/04/07 07:59:49 (1 year ago)
Author:
russellm
Message:

Fixed #5212, #5222 -- Added the ability for users to register their own commands with django-admin. A previous attempt at this was introduced in [5923]-[5925], and rolled out in [5929].

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/core/management/__init__.py

    r5929 r6047  
    11import django 
     2from django.core.management.base import CommandError 
    23from optparse import OptionParser 
    34import os 
     
    89get_version = django.get_version 
    910 
    10 def load_command_class(name): 
     11# A cache of loaded commands, so that call_command  
     12# doesn't have to reload every time it is called 
     13_commands = None 
     14     
     15def find_commands(path): 
     16    """ 
     17    Given a path to a management directory, return a list of all the command names  
     18    that are available. Returns an empty list if no commands are defined. 
     19    """ 
     20    command_dir = os.path.join(path, 'commands') 
     21    try: 
     22        return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')] 
     23    except OSError: 
     24        return [] 
     25 
     26def load_command_class(module, name): 
    1127    """ 
    1228    Given a command name, returns the Command class instance. Raises 
    13     ImportError if it doesn't exist. 
    14     """ 
    15     # Let the ImportError propogate. 
    16     return getattr(__import__('django.core.management.commands.%s' % name, {}, {}, ['Command']), 'Command')() 
     29    Raises ImportError if a command module doesn't exist, or AttributeError 
     30    if a command module doesn't contain a Command instance. 
     31    """ 
     32    # Let any errors propogate. 
     33    return getattr(__import__('%s.management.commands.%s' % (module, name), {}, {}, ['Command']), 'Command')() 
     34 
     35def get_commands(load_user_commands=True): 
     36    """ 
     37    Returns a dictionary of instances of all available Command classes. 
     38    Core commands are always included; user-register commands will also 
     39    be included if ``load_user_commands`` is True. 
     40 
     41    This works by looking for a management.commands package in  
     42    django.core, and in each installed application -- if a commands  
     43    package exists, it loads all commands in that application. 
     44 
     45    The dictionary is in the format {name: command_instance}. 
     46     
     47    The dictionary is cached on the first call, and reused on subsequent 
     48    calls. 
     49    """ 
     50    global _commands 
     51    if _commands is None: 
     52        _commands = dict([(name, load_command_class('django.core',name))  
     53                            for name in find_commands(__path__[0])]) 
     54        if load_user_commands: 
     55            # Get commands from all installed apps 
     56            from django.db import models 
     57            for app in models.get_apps(): 
     58                try: 
     59                    app_name = '.'.join(app.__name__.split('.')[:-1]) 
     60                    path = os.path.join(os.path.dirname(app.__file__),'management') 
     61                    _commands.update(dict([(name, load_command_class(app_name,name))  
     62                                                    for name in find_commands(path)])) 
     63                except AttributeError: 
     64                    raise CommandError, "Management command '%s' in application '%s' doesn't contain a Command instance.\n" % (name, app_name) 
     65    return _commands 
    1766 
    1867def call_command(name, *args, **options): 
     
    2776        call_command('sqlall', 'myapp') 
    2877    """ 
    29     klass = load_command_class(name) 
    30     return klass.execute(*args, **options) 
    31  
     78    try: 
     79        command = get_commands()[name] 
     80    except KeyError: 
     81        raise CommandError, "Unknown command: %r\n" % name 
     82    return command.execute(*args, **options) 
     83     
    3284class ManagementUtility(object): 
    3385    """ 
     
    3890    """ 
    3991    def __init__(self): 
    40         self.commands = self.default_commands() 
    41  
    42     def default_commands(self): 
    43         """ 
    44         Returns a dictionary of instances of all available Command classes. 
    45  
    46         This works by looking for and loading all Python modules in the 
    47         django.core.management.commands package. 
    48  
    49         The dictionary is in the format {name: command_instance}. 
    50         """ 
    51         command_dir = os.path.join(__path__[0], 'commands') 
    52         names = [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')] 
    53         return dict([(name, load_command_class(name)) for name in names]) 
     92        # The base management utility doesn't expose any user-defined commands 
     93        try: 
     94            self.commands = get_commands(load_user_commands=False) 
     95        except CommandError, e: 
     96            sys.stderr.write(str(e)) 
     97            sys.exit(1) 
    5498 
    5599    def usage(self): 
     
    134178    """ 
    135179    def __init__(self, project_directory): 
    136         super(ProjectManagementUtility, self).__init__() 
     180        try: 
     181            self.commands = get_commands() 
     182        except CommandError, e: 
     183            sys.stderr.write(str(e)) 
     184            sys.exit(1) 
    137185 
    138186        # Remove the "startproject" command from self.commands, because 
  • django/trunk/docs/django-admin.txt

    r6017 r6047  
    620620    * Type ``sql``, then [TAB], to see all available options whose names start 
    621621      with ``sql``. 
     622 
     623Customized actions 
     624================== 
     625 
     626**New in Django development version** 
     627 
     628If you want to add an action of your own to ``manage.py``, you can. 
     629Simply add a ``management/commands`` directory to your application. 
     630Each python module in that directory will be discovered and registered as 
     631a command that can be executed as an action when you run ``manage.py``:: 
     632 
     633    /fancy_blog 
     634        __init__.py 
     635        models.py 
     636        /management 
     637            __init__.py 
     638            /commands 
     639                __init__.py 
     640                explode.py 
     641        views.py 
     642         
     643In this example, ``explode`` command will be made available to any project 
     644that includes the ``fancy_blog`` application in ``settings.INSTALLED_APPS``. 
     645 
     646The ``explode.py`` module has only one requirement -- it must define a class 
     647called ``Command`` that extends ``django.core.management.base.BaseCommand``. 
     648 
     649For more details on how to define your own commands, look at the code for the 
     650existing ``django-admin.py`` commands, in ``/django/core/management/commands``.