Login

extras.py for management commands

Author:
dnordberg
Posted:
August 22, 2007
Language:
Python
Version:
.96
Score:
2 (after 2 ratings)

! Note - no longer needed

Save this script in the same directory as manage.py and run it through the command line.

It picks up project Command class instances. Something that will hopefully be fixed in the Django SVN version soon.

Heres an example of a command:

utils/management/commands/sqlallall.py

from django.core.management import call_command from django.core.management.base import BaseCommand from django.db import models

class Command(BaseCommand): help = "Returns sqlall for all installed apps."

def handle(self, *args, **options):
    """
    Returns sqlall for all installed apps.
    """

    for app in models.get_apps():
        call_command("sqlall", app.__name__.split(".")[-2])
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
from django.core.management import setup_environ
from optparse import OptionParser
import os
import sys
import textwrap
import logging

_PATH_TO_DJANGO_MANAGEMENT="../django/core/management"

try:
    import settings # Assumed to be in the same directory.
except ImportError:
    sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
    sys.exit(1)

_DJANGO_COMMANDS = {}

def find_commands(path):
    """
    Given a path to a management directory, return a list of all the command names 
    that are available. Returns an empty list if no commands are defined.
    """
    command_dir = os.path.join(path, 'commands')
    try:
        return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
    except OSError:
        return []
    
def load_command_class(name, module=None):
    """
    Given a command name, returns the Command class instance. Raises
    Raises ImportError if a command module doesn't exist, or AttributeError
    if a command module doesn't include .
    """
    # Let any errors propogate.
    if module:
        return getattr(__import__('%s.management.commands.%s' % (module, name), {}, {}, ['Command']), 'Command')()
    else:
        return getattr(__import__('django.core.management.commands.%s' % (name ), {}, {}, ['Command']), 'Command')()

def call_command(name, *args, **options):
    """
    Calls the given command, with the given options and args/kwargs.
    
    This is the primary API you should use for calling specific commands.
    
    Some examples:
        call_command('syncdb')
        call_command('shell', plain=True)
        call_command('sqlall', 'myapp')
    """
    klass = getattr(__import__(_DJANGO_COMMANDS[name].__module__, {}, {}, ['Command']), 'Command')()
    return klass.execute(*args, **options)

class ManagementUtility(object):
    """
    Encapsulates the logic of the django-admin.py and manage.py utilities.

    A ManagementUtility has a number of commands, which can be manipulated
    by editing the self.commands dictionary.
    """
    def __init__(self):
        self.commands = self.default_commands()

    def default_commands(self):
        """
        Returns a dictionary of instances of all available Command classes.

        This works by looking for and loading all Python modules in the
        django.core.management.commands package.

        The dictionary is in the format {name: command_instance}.
        """
        command_dir = os.path.join(_PATH_TO_DJANGO_MANAGEMENT, 'commands')
        names = [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')]
        commands = dict([(name, load_command_class(name)) for name in names])
        _DJANGO_COMMANDS = commands
        return commands

class ProjectManagementUtility(ManagementUtility):
    """
    Encapsulates the logic of the django-admin.py and manage.py utilities.

    A ManagementUtility has a number of commands, which can be manipulated
    by editing the self.commands dictionary.
    """
    def __init__(self):
        self.commands = {}
        self.commands = self.default_commands()

    def default_commands(self):
        """
        Returns a dictionary of instances of all available Command classes.

        This works by looking for and loading all Python modules in the
        django.core.management.commands package. It also looks for a
        management.commands package in each installed application -- if
        a commands package exists, it loads all commands in that application.

        The dictionary is in the format {name: command_instance}.
        """
        from django.db import models
        
        # Base command set 
        #commands = super(ProjectManagementUtility, self).default_commands() 
        commands = {}

        # Get commands from all installed apps
        for app in models.get_apps():
            try:
                app_name = '.'.join(app.__name__.split('.')[:-1])
                path = os.path.join(os.path.dirname(app.__file__),'management')
                commands.update(dict([(name, load_command_class(name, app_name)) for name in find_commands(path)]))
            except AttributeError:
                sys.stderr.write("Management command '%s' in application '%s' doesn't contain a Command instance.\n" % (name, app_name))
                sys.exit(1)
                
        _DJANGO_COMMANDS = commands
        return commands

    def usage(self):
        """
        Returns a usage string, for use with optparse.

        The string doesn't include the options (e.g., "--verbose"), because
        optparse puts those in automatically.
        """
        usage = ["%prog command [options]\nactions:"]
        commands = self.commands.items()
        commands.sort()
        for name, cmd in commands:
            usage.append('  %s %s' % (name, cmd.args))
            usage.extend(textwrap.wrap(cmd.help, initial_indent='    ', subsequent_indent='    '))
            usage.append('')
        return '\n'.join(usage[:-1]) # Cut off the last list element, an empty space.

    def execute(self, argv=None):
        """
        Parses the given argv from the command line, determines which command
        to run and runs the command.
        """
        
        if argv is None:
            argv = sys.argv

        parser = OptionParser(usage=self.usage())
        
        parser.add_option("--log",
                    action="store", type="string", dest="logfile", default=None, help="Log messages to a file."),
        parser.add_option('--settings',
            help='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.')
        parser.add_option('--pythonpath',
            help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".')
        parser.add_option('--format', default='json', dest='format',
            help='Specifies the output serialization format for fixtures')
        parser.add_option('--indent', default=None, dest='indent',
            type='int', help='Specifies the indent level to use when pretty-printing output')
        parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
            type='choice', choices=['0', '1', '2'],
            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output')
        options, args = parser.parse_args(argv[1:])

        # If the 'settings' or 'pythonpath' options were submitted, activate those.
        if options.settings:
            os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
        if options.pythonpath:
            sys.path.insert(0, options.pythonpath)
            
        # Set logging
        level = logging.INFO
        i = 0
        while i < int(options.verbosity):
            level -= 10
            i += 1
    
        logging.basicConfig(level=level,
                        format='%(asctime)s | %(levelname)s | %(message)s',
                        datefmt='%d-%m %H:%M',
                        filename=options.logfile,
                        filemode='w+')
        
        try:
            command_name = args[0]
        except IndexError:
            sys.stderr.write("Type '%s --help' for usage.\n" % os.path.basename(argv[0]))
            sys.exit(1)
        try:
            command = self.commands[command_name]
        except KeyError:
            sys.stderr.write("Unknown command: %r\nType '%s --help' for usage.\n" % (command_name, os.path.basename(argv[0])))
            sys.exit(1)
        command.execute(*args[1:], **options.__dict__)
        

def execute_from_custom_command_line(settings_mod, argv=None):
    """
    A simple method that runs a ManagementUtility.
    """
    setup_environ(settings_mod)
    utility = ProjectManagementUtility()
    utility.execute(argv)

if __name__ == "__main__":
    execute_from_custom_command_line(settings)

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 11 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 months ago

Comments

dnordberg (on April 4, 2010):

not needed since management commands were fixed for django

#

Please login first before commenting.