There is a way to add features to an existing django command?
I want to run a command just before the a django command is started.
For example:
$ python manage.py runserver
Validating models...
0 errors found
Django version 1.3, using settings 'creat1va.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
(开发者_JAVA技巧started some command in the background)
[10/Jul/2011 21:50:26] "GET / HTTP/1.1" 200 1611
[10/Jul/2011 21:50:26] "GET /assets/css/master.css HTTP/1.1" 404 1783
[10/Jul/2011 21:50:26] "GET /assets/images/misc/logo.png HTTP/1.1" 404 1801
[10/Jul/2011 21:50:26] "GET /assets/images/icons/bo.gif HTTP/1.1" 404 1798
[10/Jul/2011 21:50:28] (My background process) "Some nice Feedback"
The main idea is to start a background process, and output the logging.
Is there a way to achieve this, without hacking the django sources?
Just realize that you can override the commands just easily as making an app with a command with the same name.
So I create an app and create a file with the same name as runserver, and later on that extend the runserver base class to add a new feature before it runs.
For example, I want to run the command $ compass watch, just before runserver starts and keep it running along runserver execution.
"""
Start $compass watch, command when you do $python manage.py runserver
file: main/management/commands/runserver.py
Add ´main´ app to the last of the installed apps
"""
from optparse import make_option
import os
import subprocess
from django.core.management.base import BaseCommand, CommandError
from django.core.management.commands.runserver import BaseRunserverCommand
from django.conf import settings
class Command(BaseRunserverCommand):
option_list = BaseRunserverCommand.option_list + (
make_option('--adminmedia', dest='admin_media_path', default='',
help='Specifies the directory from which to serve admin media.'),
make_option('--watch', dest='compass_project_path', default=settings.MEDIA_ROOT,
help='Specifies the project directory for compass.'),
)
def inner_run(self, *args, **options):
self.compass_project_path = options.get('compass_project_path', settings.MEDIA_ROOT)
self.stdout.write("Starting the compass watch command for %r\n" % self.compass_project_path)
self.compass_pid = subprocess.Popen(["compass watch %s" % self.compass_project_path],
shell=True,
stdin=subprocess.PIPE,
stdout=self.stdout,
stderr=self.stderr)
self.stdout.write("Compas watch process on %r\n" % self.compass_pid.pid)
super(Command, self).inner_run(*args, **options)
This works just fine.
Look at https://docs.djangoproject.com/en/dev/howto/custom-management-commands/ for more details about django commands
Hope someone find this helpful
To further expand on @Mario César's excellent answer, I would like to provide a modern version of his initial 2011 code adapted for Django 1.8+:
Before Django 1.8, management commands were based on the optparse module [...] Now that management commands use argparse for argument parsing, all arguments are passed in **options by default [...]
Source
Additionally, I would like to point out that the specific command runserver
that was chosen in the question has a slight complication making it both a good and bad example.
Bad example, because the complication is that the command is overridden by Django itself as well. Indeed, Django uses the same method as proposed by Mario: Django overrides it in the staticfiles app (see Django code on github) in order to offer the additional static files options.
Therefore, it is better to override the staticfiles app command rather than the core command, if one uses static. This answers to @ts_pati's comment too on why there is problem. The Django code of staticfiles is the good example on how to override it, but this time importing the staticfiles in order not to lose that functionality:
from django.contrib.staticfiles.management.commands.runserver import Command as StaticfilesRunserverCommand
class Command(StaticfilesRunserverCommand):
help = "Starts a lightweight Web server for development, serves static files and does some custom fancy stuff."
def add_arguments(self, parser):
super(Command, self).add_arguments(parser)
parser.add_argument('--my-custom-argument', action="...", dest='my_custom_handler', default=True, help='do some stuff in fancy ways')
def get_handler(self, *args, **options):
"""
My fancy stuff function.
"""
handler = super(Command, self).get_handler(*args, **options)
my_custom_handler = options.get('my_custom_handler', True)
# do stuff here
return handler
EDIT: I would also like to add the order of this in INSTALLED_APPS
is apparently important and it has to be before django.contrib.staticfiles
.
Write your own management command in your app that runs your command and then calls Django's built-in implementation.
精彩评论