(Django) Create a management command that will ove

2019-05-26 10:41发布

问题:

We always run our tests off of settings_test, like so: ./manage.py test someapp --settings=settings_test. The problem is that it's sometimes problematic to remember to add the option.

I'd like to introduce a common app that just has the management command test.py. Depending on it's placement in the INSTALLED_APPS setting, it will override the default. Inside the command itself, I'd like to change the default of the --settings option. How can I do that?

I am aware that I can create a local.py file that is similar to manage.py but with settings_test instead of settings. However, the point is to still run ./manage.py, but with having settings_test as default instead of constantly typing "--settings=settings_test" after ./manage.py test someapp

回答1:

After several attempts, I found that manage.py sets the settings long enough before the actual management command gets called that it's basically impossible (as far as I can tell) to change them there. Eventually I decided that, since it's seems to be OK to alter manage.py - there's your default settings file there, for instance - that would be a reasonable place to deal with this, so I implemented it there:

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")

    argv = sys.argv
    try:
        if argv[1] == 'test' and not any([k.startswith('--settings') for k in argv]):
            os.environ["DJANGO_SETTINGS_MODULE"] = "myapp.test_settings"
    except IndexError:
        pass

    from django.core.management import execute_from_command_line
    execute_from_command_line(argv)

This seems to work as expected and I don't see any major disadvantage or problem - happy to be corrected.



回答2:

You can override default commands by implemeting them in your app (say: common_app).

Create a management.commands package in common_app. And implement a test command in there:

# this is commonapp/management/commands/test.py
try:
    from south.management.commands import test
except ImportError:
    from django.core.management.commands import test


class Command(test.Command):
    def handle(self, *args, **kwargs):
        kwargs['settings'] = kwargs.get('settings', 'common_app.settings')
        super(Command, self).handle(*args, **kwargs)

This will use the settings.py file in common_app if there's no '--settings=' flag in given. But you can change that string in "settings_test" and it will load the first settings_test.py it can find on your python path.

South does this command overriding too, so for completeness I added the south import. But if any of your other installed apps also override the test command... you get the idea.

Don't forget the empty __init__.py files to make 'management' and 'commands' packages.

RTFM for more info on Django custom management commands.



回答3:

You can override a django command as @Chris Wesseling describe in his answer.

Note: if there are other apps that are extending the command, move your app above those apps in the INSTALLED_APPS list, i.e.

  • to override runserver command and you are using 'django.contrib.staticfiles', place your app before staticfiles app
  • to override test command and you are using a test app i.e. django_nose, the same, place your app before django_nose app