| 15 | | # Let the ImportError propogate. |
|---|
| 16 | | return getattr(__import__('django.core.management.commands.%s' % name, {}, {}, ['Command']), 'Command')() |
|---|
| | 15 | command_dir = os.path.join(path, 'commands') |
|---|
| | 16 | try: |
|---|
| | 17 | return [f[:-3] for f in os.listdir(command_dir) if not f.startswith('_') and f.endswith('.py')] |
|---|
| | 18 | except OSError: |
|---|
| | 19 | return [] |
|---|
| | 20 | |
|---|
| | 21 | def load_default_commands(): |
|---|
| | 22 | """ |
|---|
| | 23 | Returns a dictionary of instances of all available Command classes. |
|---|
| | 24 | |
|---|
| | 25 | This works by looking for and loading all Python modules in the |
|---|
| | 26 | django.core.management.commands package. |
|---|
| | 27 | |
|---|
| | 28 | The dictionary is in the format {name: command_instance}. |
|---|
| | 29 | """ |
|---|
| | 30 | return dict([(name, getattr(__import__('django.core.management.commands.%s' % (name), {}, {}, ['Command']), 'Command')()) for name in find_commands(__path__[0])]) |
|---|
| | 31 | |
|---|
| | 32 | def load_project_commands(): |
|---|
| | 33 | """ |
|---|
| | 34 | Returns a dictionary of instances of all available Command classes. |
|---|
| | 35 | |
|---|
| | 36 | It looks for a management.commands package in each installed application |
|---|
| | 37 | -- if a commands package exists, it loads all commands in that |
|---|
| | 38 | application and raises an AttributeError if a command doesn't contain a |
|---|
| | 39 | Command instance. |
|---|
| | 40 | |
|---|
| | 41 | The dictionary is in the format {name: command_instance}. |
|---|
| | 42 | """ |
|---|
| | 43 | |
|---|
| | 44 | commands = {} |
|---|
| | 45 | |
|---|
| | 46 | from django.db import models |
|---|
| | 47 | |
|---|
| | 48 | # Get commands from all installed apps |
|---|
| | 49 | for app in models.get_apps(): |
|---|
| | 50 | try: |
|---|
| | 51 | app_name = '.'.join(app.__name__.split('.')[:-1]) |
|---|
| | 52 | path = os.path.join(os.path.dirname(app.__file__),'management') |
|---|
| | 53 | commands.update(dict([(name, getattr(__import__('%s.management.commands.%s' % (app_name, name), {}, {}, ['Command']), 'Command')()) for name in find_commands(path)])) |
|---|
| | 54 | except AttributeError: |
|---|
| | 55 | sys.stderr.write("Management command '%s' in application '%s' doesn't contain a Command instance.\n" % (name, app_name)) |
|---|
| | 56 | sys.exit(1) |
|---|
| | 57 | |
|---|
| | 58 | return commands |
|---|
| 55 | 84 | def usage(self): |
|---|
| 56 | 85 | """ |
|---|
| 57 | 86 | Returns a usage string, for use with optparse. |
|---|
| 58 | 87 | |
|---|
| 59 | 88 | The string doesn't include the options (e.g., "--verbose"), because |
|---|
| 60 | 89 | optparse puts those in automatically. |
|---|
| 61 | 90 | """ |
|---|
| 62 | 91 | usage = ["%prog command [options]\nactions:"] |
|---|
| 63 | 92 | commands = self.commands.items() |
|---|
| 64 | 93 | commands.sort() |
|---|
| 65 | 94 | for name, cmd in commands: |
|---|
| 66 | 95 | usage.append(' %s %s' % (name, cmd.args)) |
|---|
| 67 | 96 | usage.extend(textwrap.wrap(cmd.help, initial_indent=' ', subsequent_indent=' ')) |
|---|
| 68 | 97 | usage.append('') |
|---|
| 69 | 98 | return '\n'.join(usage[:-1]) # Cut off the last list element, an empty space. |
|---|
| 70 | 99 | |
|---|
| 71 | 100 | def execute(self, argv=None): |
|---|
| 72 | 101 | """ |
|---|
| 73 | 102 | Parses the given argv from the command line, determines which command |
|---|
| 74 | 103 | to run and runs the command. |
|---|
| 75 | 104 | """ |
|---|
| 76 | 105 | if argv is None: |
|---|
| 77 | 106 | argv = sys.argv |
|---|
| 78 | 107 | |
|---|
| 79 | 108 | # Create the parser object and parse the command-line args. |
|---|
| 80 | 109 | # TODO: Ideally each Command class would register its own options for |
|---|
| 81 | 110 | # add_option(), but we'd need to figure out how to allow for multiple |
|---|
| 82 | 111 | # Commands using the same options. The optparse library gets in the way |
|---|
| 83 | 112 | # by checking for conflicts: |
|---|
| 84 | 113 | # http://docs.python.org/lib/optparse-conflicts-between-options.html |
|---|
| 85 | 114 | parser = OptionParser(usage=self.usage(), version=get_version()) |
|---|
| 86 | 115 | parser.add_option('--settings', |
|---|
| 87 | 116 | 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.') |
|---|
| 88 | 117 | parser.add_option('--pythonpath', |
|---|
| 89 | 118 | help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".') |
|---|
| 90 | 119 | parser.add_option('--plain', action='store_true', dest='plain', |
|---|
| 91 | 120 | help='When using "shell": Tells Django to use plain Python, not IPython.') |
|---|
| 92 | 121 | parser.add_option('--noinput', action='store_false', dest='interactive', default=True, |
|---|
| 93 | 122 | help='Tells Django to NOT prompt the user for input of any kind.') |
|---|
| 94 | 123 | parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True, |
|---|
| 95 | 124 | help='When using "runserver": Tells Django to NOT use the auto-reloader.') |
|---|
| 96 | 125 | parser.add_option('--format', default='json', dest='format', |
|---|
| 97 | 126 | help='Specifies the output serialization format for fixtures') |
|---|
| 98 | 127 | parser.add_option('--indent', default=None, dest='indent', |
|---|
| 99 | 128 | type='int', help='Specifies the indent level to use when pretty-printing output') |
|---|
| 100 | 129 | parser.add_option('--verbosity', action='store', dest='verbosity', default='1', |
|---|
| 101 | 130 | type='choice', choices=['0', '1', '2'], |
|---|
| 102 | 131 | help='Verbosity level; 0=minimal output, 1=normal output, 2=all output') |
|---|
| 103 | 132 | parser.add_option('--adminmedia', dest='admin_media_path', default='', |
|---|
| 104 | 133 | help='When using "runserver": Specifies the directory from which to serve admin media.') |
|---|
| 105 | 134 | options, args = parser.parse_args(argv[1:]) |
|---|
| 106 | 135 | |
|---|
| 107 | 136 | # If the 'settings' or 'pythonpath' options were submitted, activate those. |
|---|
| 108 | 137 | if options.settings: |
|---|
| 109 | 138 | os.environ['DJANGO_SETTINGS_MODULE'] = options.settings |
|---|
| 110 | 139 | if options.pythonpath: |
|---|
| 111 | 140 | sys.path.insert(0, options.pythonpath) |
|---|
| 112 | 141 | |
|---|
| 113 | 142 | # Run the appropriate command. |
|---|
| 114 | 143 | try: |
|---|
| 115 | 144 | command_name = args[0] |
|---|
| 116 | 145 | except IndexError: |
|---|
| 117 | 146 | sys.stderr.write("Type '%s --help' for usage.\n" % os.path.basename(argv[0])) |
|---|
| 118 | 147 | sys.exit(1) |
|---|
| 119 | 148 | try: |
|---|
| 120 | 149 | command = self.commands[command_name] |
|---|
| 121 | 150 | except KeyError: |
|---|
| 122 | 151 | sys.stderr.write("Unknown command: %r\nType '%s --help' for usage.\n" % (command_name, os.path.basename(argv[0]))) |
|---|
| 123 | 152 | sys.exit(1) |
|---|
| 124 | 153 | command.execute(*args[1:], **options.__dict__) |
|---|
| 125 | 154 | |
|---|
| 126 | 155 | class ProjectManagementUtility(ManagementUtility): |
|---|
| 127 | 156 | """ |
|---|
| 128 | 157 | A ManagementUtility that is specific to a particular Django project. |
|---|
| 129 | 158 | As such, its commands are slightly different than those of its parent |
|---|
| 130 | 159 | class. |
|---|
| 131 | 160 | |
|---|
| 132 | 161 | In practice, this class represents manage.py, whereas ManagementUtility |
|---|
| 133 | 162 | represents django-admin.py. |
|---|
| 134 | 163 | """ |
|---|
| 135 | 164 | def __init__(self, project_directory): |
|---|
| 136 | 165 | super(ProjectManagementUtility, self).__init__() |
|---|
| 137 | 166 | |
|---|
| 138 | 167 | # Remove the "startproject" command from self.commands, because |
|---|
| 139 | 168 | # that's a django-admin.py command, not a manage.py command. |
|---|
| 140 | 169 | del self.commands['startproject'] |
|---|
| 141 | 170 | |
|---|
| 142 | 171 | # Override the startapp command so that it always uses the |
|---|
| 143 | 172 | # project_directory, not the current working directory (which is default). |
|---|
| 144 | 173 | from django.core.management.commands.startapp import ProjectCommand |
|---|
| 145 | 174 | self.commands['startapp'] = ProjectCommand(project_directory) |
|---|
| 146 | 175 | |
|---|
| 147 | 176 | def setup_environ(settings_mod): |
|---|
| 148 | 177 | """ |
|---|
| 149 | 178 | Configure the runtime environment. This can also be used by external |
|---|
| 150 | 179 | scripts wanting to set up a similar environment to manage.py. |
|---|
| 151 | 180 | """ |
|---|
| 152 | 181 | # Add this project to sys.path so that it's importable in the conventional |
|---|
| 153 | 182 | # way. For example, if this file (manage.py) lives in a directory |
|---|
| 154 | 183 | # "myproject", this code would add "/path/to/myproject" to sys.path. |
|---|
| 155 | 184 | project_directory, settings_filename = os.path.split(settings_mod.__file__) |
|---|
| 156 | 185 | project_name = os.path.basename(project_directory) |
|---|
| 157 | 186 | settings_name = os.path.splitext(settings_filename)[0] |
|---|
| 158 | 187 | sys.path.append(os.path.join(project_directory, '..')) |
|---|
| 159 | 188 | project_module = __import__(project_name, {}, {}, ['']) |
|---|
| 160 | 189 | sys.path.pop() |
|---|
| 161 | 190 | |
|---|
| 162 | 191 | # Set DJANGO_SETTINGS_MODULE appropriately. |
|---|
| 163 | 192 | os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name) |
|---|